Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>EnvTruth: Env Var Boolean and Number CheckerNew to Visual Studio Code? Get it now.
EnvTruth: Env Var Boolean and Number Checker

EnvTruth: Env Var Boolean and Number Checker

jaytank_dev

| (0) | Free
Catches environment variables used as booleans or numbers without parsing in Python and JS/TS: if os.getenv("DEBUG") is true for DEBUG=false, process.env.FLAG === true is always false, process.env.PORT + 1 gives "30001". Quick Fixes, hover with where each variable is defined, fully offline.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

EnvTruth: Env Var Boolean and Number Checker

Environment variables are always strings. That one fact causes a whole family of quiet bugs:

DEBUG = os.environ.get("DEBUG", False)   # "false" in .env -> DEBUG is the string "false"
if DEBUG:                                 # ... which is truthy, so debug mode is ON
    ...
workers = int(os.getenv("WORKERS"))       # TypeError the day WORKERS is not set
if (process.env.FEATURE_BETA) { ... }     // FEATURE_BETA=false still enables the feature
if (process.env.FLAG === true) { ... }    // never true: FLAG is a string or undefined
const next = process.env.PORT + 1;        // "3000" + 1 is "30001"

People hit this constantly (Django forum: "env variables can never seem to be false", python-dotenv issue #291), and the usual linters do not flag it. EnvTruth does, in Python and JavaScript/TypeScript, and a Quick Fix rewrites each one into a correct parse.

What you see

  • Problems and squiggles on the exact expression, with a message that explains what really happens ("false", "0" and "no" are all truthy, "3000" + 1 is "30001", raises TypeError when WORKERS is unset).
  • Quick Fixes (lightbulb) with a safe rewrite for each finding.
  • Activity bar: an EnvTruth icon opens the Env checks view. Findings are grouped by file, and each row names the rule and the variable (for example ET001 DEBUG with "string used as boolean"), so rows are easy to tell apart. Click a row to jump to it, or use the inline lightbulb button to apply its Quick Fix. A badge on the icon shows the number of findings.
  • Hover on any env read to see where that variable is defined in the workspace (.env, .env.*, *.env, docker compose environment:, Kubernetes env:, workflow env: blocks) and its value there. Only boolean-looking and short numeric values are shown. Everything else (keys, URLs, tokens, long numbers) is masked as masked (N chars).
  • Status bar: EnvTruth: N. Click it to open the view.

Open files are checked as you type. The rest of the workspace is scanned in the background.

Rules

ID Rule Default Example Quick Fix
ET001 Env string used as a boolean by truthiness Warning if os.getenv("DEBUG"):, bool(os.environ.get("FEATURE_X")), not os.getenv("VERBOSE"), if (process.env.DEBUG), !!process.env.FLAG, Boolean(process.env.FLAG), process.env.X ? a : b, process.env.DEBUG && log(), import.meta.env.VITE_DEBUG os.getenv("DEBUG", "").strip().lower() in ("1", "true", "yes", "on") / ["1", "true", "yes", "on"].includes((process.env.DEBUG ?? "").trim().toLowerCase())
ET002 Env value compared to a boolean literal Error process.env.FLAG === true (always false), os.getenv("DEBUG") == True, is False The same boolean parse (negated for == False, !== true)
ET003 Env value used as a number without parsing Warning process.env.PORT + 1, process.env.TIMEOUT > 5000, process.env.PORT === 8080, os.getenv("PORT") + 1, os.getenv("WORKERS") > 4 Number(process.env.PORT ?? "0") / int(os.getenv("PORT", "0")) (float for float literals; an existing default is kept)
ET004 Conversion that crashes when unset Warning int(os.getenv("WORKERS")), float(os.environ.get("RATIO")), json.loads(os.getenv("CFG")), JSON.parse(process.env.CFG) Add a default: int(os.getenv("WORKERS", "0")), JSON.parse(process.env.CFG ?? "null")
ET005 Non-string default Warning os.getenv("DEBUG", False), os.environ.get("RETRIES", 3): a str when set, a bool/int when unset int(os.environ.get("RETRIES", "3")), or a boolean parse for True/False defaults

When one expression triggers ET005 together with another rule (if os.getenv("DEBUG", False):), only the more specific finding is shown, and its fix handles the default too.

What ET001 reports, and what it leaves alone

A truthiness check is only a bug when the variable is meant to be a flag. if not os.getenv("API_KEY"): raise is an intended presence check and is fine. EnvTruth reports a truthiness check when:

  • the name looks like a flag: DEBUG, VERBOSE, DRY_RUN, ENABLE*, DISABLE*, FEATURE*, USE_*, IS_*, HAS_*, ALLOW_*, SKIP_*, NO_*, FORCE_*, *_ENABLED, *_DISABLED, *_FLAG, *_ON, *_OFF, *_DEBUG (framework prefixes like VITE_, NEXT_PUBLIC_, REACT_APP_ are ignored), or
  • the code passes a boolean default (os.getenv("X", False)), or
  • the variable is set to true/false/yes/no/on/off/0/1 in any .env, compose or Kubernetes file in the workspace.

Names built from the words in envTruth.presenceNames are treated as presence checks and never reported: by default KEY, TOKEN, SECRET, PASSWORD, PASSWD, URL, URI, HOST, DSN, PATH, DIR, FILE, ENDPOINT and NO_COLOR. A word matches a whole name (NO_COLOR) or the start or end of any _-separated part (API_KEY, APIKEY, REDIS_HOSTNAME). A name that also looks like a flag (USE_API_KEY, KEYCLOAK_ENABLED) is still checked, unless it equals a listed word exactly.

Also never reported:

  • Vite's built-in booleans import.meta.env.DEV, PROD and SSR.
  • Anything inside comments and strings (including template literals, f-strings and docstrings).
  • Reads that are already parsed or compared as strings: os.getenv("DEBUG", "").lower() == "true", process.env.DEBUG === "true", os.getenv("X", "").strip().lower() in (...), Number(process.env.PORT).
  • Value defaults such as os.getenv("REGION") or "us-east-1" and process.env.PORT || 3000.

Settings

Setting Default Description
envTruth.enabled true Turn all checks on or off.
envTruth.rules {} Severity per rule (error, warning, information, hint) or off, e.g. { "ET002": "error", "ET005": "off" }.
envTruth.presenceNames see above Words that mark a variable as a presence check (ET001 only). Setting this replaces the default list.
envTruth.maxFiles 2000 Maximum number of source files scanned in the workspace. Files open in an editor are always checked. Files over 1 MB are skipped.
envTruth.exclude node_modules, .git, dist, build, out, vendor, venv, .venv, __pycache__, .next, coverage, site-packages Glob patterns that are never scanned. node_modules, .git, dist, build, vendor, venv and .venv are always excluded.

Settings apply immediately, without a reload.

Commands

  • EnvTruth: Rescan Workspace (also the refresh button in the view title)
  • EnvTruth: Show Env Checks
  • EnvTruth: Open Settings (gear button in the view title)
  • Apply Quick Fix (inline button on each fixable row)

Languages

Python (.py, .pyw) and JavaScript / TypeScript (.js, .jsx, .mjs, .cjs, .ts, .tsx, .mts, .cts). Recognised reads: os.getenv(...), os.environ.get(...), os.environ[...] (plus getenv / environ imported with from os import ...), process.env.X, process.env["X"], import.meta.env.X.

Privacy and safety

  • No network, no telemetry.
  • EnvTruth only reads files inside the workspace, through VS Code's file APIs. Symlinks that lead outside the workspace are ignored, and files over 1 MB are skipped.
  • It never runs processes, so it works fully in untrusted workspaces.
  • Values from .env and deployment files stay on your machine. The hover only shows values that look boolean or are short numbers.

Limitations

  • The analysis is per expression and does not follow data flow: DEBUG = os.getenv("DEBUG") followed later by if DEBUG: is not linked (DEBUG = os.getenv("DEBUG", False) and DEBUG = bool(os.getenv("DEBUG")) are reported). Destructured reads such as const { DEBUG } = process.env are not tracked either.
  • Only string-literal variable names are recognised (os.getenv(name) with a variable is skipped), and os imported under another name is not followed.
  • ET003 needs a number literal on the other side of the operator (process.env.PORT + offset is not checked).
  • ET004 does not look for a surrounding try/except or try/catch.
  • The YAML reader understands the common compose and Kubernetes env shapes (list, map, name/value, valueFrom, one-line {name, value}), not the full YAML spec. Anchors and Helm templates are not expanded.
  • .env files and YAML files are re-read when they are saved in the editor or change on disk. If your system's file watcher limit is exhausted, use Rescan Workspace after changing files outside the editor.

License

MIT - included with the extension.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft