In TypeScript, process.env.DATABASE_URL has type string | undefined. Adding a non-null assertion — process.env.DATABASE_URL! — tells the compiler to treat it as string. The compiler is satisfied. TypeScript doesn't complain. Your application crashes in production when the environment variable isn't set.
Why this is so tempting
TypeScript's strict null checks are one of its best features — they prevent null reference errors at compile time. But environment variables are inherently runtime values. The compiler can't know whether DATABASE_URL will be set when the code runs.
The non-null assertion (!) is the path of least resistance: it makes the type error go away instantly. AI assistants reach for it reflexively because it's the shortest fix. But it converts a compile-time safety check into a runtime crash.
What happens in practice
The application works in development because your .env file has all the variables. CI passes because the test environment is configured. Then you deploy to a new environment, miss one variable in the config, and the application crashes on startup — or worse, crashes on the first request that hits that code path.
We've seen this cause:
- Database connections that fail silently on deploy - Stripe integrations that crash when processing the first payment - Auth flows that break because a secret wasn't configured
What TYPE009 catches
TYPE009 flags every process.env.VAR! non-null assertion and suggests a validated alternative:
const DATABASE_URL = process.env.DATABASE_URL; if (!DATABASE_URL) throw new Error('DATABASE_URL is required');
Or using a validation library like zod or envalid to validate all environment variables at startup. The key insight is: fail fast and explicitly, not late and cryptically.
TYPE009 is available with a StableStack license.
pip install stablestack