← Writing

tsc exit code 0 does not mean your typecheck passed

When tsc runs out of memory, node dies with a V8 stack trace — but the wrapping command can still return exit 0 with empty output, which looks exactly like a clean check.

A lesson that cost me real debugging time: I ran a heavy tsc --noEmit over a project whose generated Prisma client is enormous, saw exit code 0 and zero error lines, and reported the typecheck clean. It wasn’t. tsc had run out of memory and crashed — node printed a V8 stack trace to stderr and died, but the wrapper returned 0, and my grep for error lines matched nothing. Real type errors sailed through undetected.

The tells of a silent OOM: frames like Builtins_InterpreterEntryTrampoline or node::StartExecution in the unfiltered tail of the output.

The fixes: cap memory explicitly (NODE_OPTIONS="--max-old-space-size=4096") so it fails loudly instead of thrashing; scope the check to a small tsconfig covering only the files you changed instead of the whole monorepo; and treat “exit 0 with suspiciously empty output” from a heavy tsc run as a failure until you’ve seen the raw tail.

← All writing Book a call →
Book a call → WhatsApp