tsc wrapper: --pretty flag suppresses errors and prints fake "compilation completed" success message
#1,772 opened on 2026年5月7日
Repository metrics
- Stars
- (48,085 stars)
- PR merge metrics
- (平均マージ 11d 1h) (30d で 45 merged PRs)
説明
Summary
When rtk tsc runs with the --pretty flag, type errors are silently swallowed and RTK reports TypeScript: No errors found even though tsc exits with a non-zero status. Without --pretty, RTK parses errors correctly. The bug is reliably reproducible.
Affected version
rtk 0.39.0 (latest at time of filing, installed via Homebrew on macOS arm64).
Reproduction
/tmp/rtk-test.ts:
const x: number = "string";
/tmp/tsconfig-rtk-test.json:
{
"compilerOptions": {
"strict": true,
"noEmit": true,
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "node"
},
"files": ["/tmp/rtk-test.ts"]
}
Run both:
$ rtk tsc --noEmit -p /tmp/tsconfig-rtk-test.json
../../../../tmp/rtk-test.ts(1,7): error TS2322: Type 'string' is not assignable to type 'number'.
═══════════════════════════════════════
TypeScript: 1 errors in 1 files
# exit code: 2
$ rtk tsc --noEmit --pretty -p /tmp/tsconfig-rtk-test.json
TypeScript: No errors found
# exit code: 2
Expected vs actual
- Expected: With
--pretty, RTK should still display the errors (or at least not lie) — minimum bar is that the textual summary matches reality whentscexits non-zero. - Actual: Exit code is correctly propagated (2), but stdout reports
No errors found. A consumer looking at output (human or LLM) sees a fake success message.
This is dangerous in CI/agent contexts: errors get hidden by a wrapper that claims success, and downstream steps (e.g. && next build) may proceed as if green. Concretely, this was discovered while running npx tsc --noEmit --pretty from a Claude Code session — the wrapper hid type errors that Vercel's build then caught, causing a failed deploy.
Root cause hypothesis
tsc --pretty emits ANSI escape codes (colors, formatting) on each error line. RTK's regex for matching tsc error lines (path(L,C): error TSxxxx: ...) does not account for embedded ANSI sequences, so it counts zero matches. With zero parsed errors, RTK synthesizes No errors found regardless of the actual exit code.
Suggested fix
Either (or both):
- Strip ANSI escape sequences from each line before regex-matching error lines.
- Cross-check parsed error count against the child exit code: if
exit != 0 && parsed_errors == 0, fall back to passthrough of the raw output rather than synthesizing a success summary. This is a good general invariant — RTK's summary should never contradict the wrapped tool's exit code.
Option 2 is the safer default since it also catches future tsc output format changes that the regex hasn't adapted to.