Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(typecheck): improve error message when tsc outputs help text#9214

Merged
sheremet-va merged 20 commits intovitest-dev:mainfrom
Ujjwaljain16:fix/typecheck-tsconfig-missing-error
Dec 23, 2025
Merged

fix(typecheck): improve error message when tsc outputs help text#9214
sheremet-va merged 20 commits intovitest-dev:mainfrom
Ujjwaljain16:fix/typecheck-tsconfig-missing-error

Conversation

@Ujjwaljain16
Copy link
Contributor

When tsconfig.json is missing and tsc cannot find any configuration file (including in parent directories), it outputs its help text instead of type checking errors. This was being captured and displayed as a confusing 'Typecheck Error' with the entire help text dump (100+ lines of tsc usage instructions).

Changes:

  1. Added help text detection in prepareResults() method

    • Checks for 'The TypeScript Compiler - Version' header
    • Checks for 'COMMON COMMANDS' section
    • Both are present in tsc help output
  2. Throws clear, actionable error message with:

    • Explanation of what went wrong
    • The configured tsconfig path (or default 'tsconfig.json')
    • Three possible solutions: a. Ensure tsconfig exists in project root b. Verify custom tsconfig path in vitest config c. Check tsconfig is valid JSON
  3. Added stderr capture in spawn() method

    • Previously only stdout was captured
    • Configuration errors from tsc may appear on stderr
    • Ensures all tsc output is examined for help text

Testing:

  • All existing tests pass (7/7 in test/typescript)
  • Manually verified tsc outputs help text when tsconfig missing
  • Automated test not included due to tsc's parent directory search behavior making it impractical to reliably trigger this scenario

Note: This is different from TS5058 error which occurs when a specific tsconfig path is provided but doesn't exist. The help text scenario happens when tsc can't locate any config file at all.

Description

Resolves #8981

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. If the feature is substantial or introduces breaking changes without a discussion, PR might be closed.
  • Ideally, include a test that fails without this PR but passes with it.
  • Please, don't make changes to pnpm-lock.yaml unless you introduce a new test example.
  • Please check Allow edits by maintainers to make review process faster. Note that this option is not available for repositories that are owned by Github organizations.

Tests

  • Run the tests with pnpm test:ci.

Documentation

  • If you introduce new functionality, document it. You can run documentation with pnpm run docs command.

Changesets

  • Changes in changelog are generated from PR name. Please, make sure that it explains your changes in an understandable manner. Please, prefix changeset messages with feat:, fix:, perf:, docs:, or chore:.

@netlify
Copy link

netlify bot commented Dec 8, 2025

Deploy Preview for vitest-dev ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 3468560
🔍 Latest deploy log https://app.netlify.com/projects/vitest-dev/deploys/694a3066ae958e0008d54f41
😎 Deploy Preview https://deploy-preview-9214--vitest-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Member

@sheremet-va sheremet-va left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, add a test that confirms the behaviour is now correct.

When tsconfig.json is missing and tsc cannot find any configuration
file (including in parent directories), it outputs its help text
instead of type checking errors. This was being captured and displayed
as a confusing 'Typecheck Error' with the entire help text dump
(100+ lines of tsc usage instructions).

Changes:
1. Added help text detection in prepareResults() method
   - Checks for 'The TypeScript Compiler - Version' header
   - Checks for 'COMMON COMMANDS' section
   - Both are present in tsc help output

2. Throws clear, actionable error message with:
   - Explanation of what went wrong
   - The configured tsconfig path (or default 'tsconfig.json')
   - Three possible solutions:
     a. Ensure tsconfig exists in project root
     b. Verify custom tsconfig path in vitest config
     c. Check tsconfig is valid JSON

3. Added stderr capture in spawn() method
   - Previously only stdout was captured
   - Configuration errors from tsc may appear on stderr
   - Ensures all tsc output is examined for help text

Testing:
- All existing tests pass (7/7 in test/typescript)
- Manually verified tsc outputs help text when tsconfig missing
- Automated test not included due to tsc's parent directory search
  behavior making it impractical to reliably trigger this scenario

Note: This is different from TS5058 error which occurs when a
specific tsconfig path is provided but doesn't exist. The help text
scenario happens when tsc can't locate any config file at all.
@Ujjwaljain16 Ujjwaljain16 force-pushed the fix/typecheck-tsconfig-missing-error branch from dfaf22a to c6f2eab Compare December 10, 2025 15:43
@Ujjwaljain16
Copy link
Contributor Author

sorry for the confusion!
Those snapshot changes were accidentally included when i staged all files i have updated the PR to remove them the commit now only contains the typecheck fix in [typechecker.ts]

@Ujjwaljain16
Copy link
Contributor Author

Ujjwaljain16 commented Dec 10, 2025

I've added unit tests in
test/typescript/test/typechecker.test.ts
that directly verify the help text detection behavior:

Detects help text with version marker - Confirms the error thrown includes the configured tsconfig path and actionable solutions
Detects help text with COMMON COMMANDS marker - Ensures detection works with partial help output
Normal tsc output passes through - Verifies regular type errors aren't affected by the new detection logic
All tests pass (3 new + 7 existing = 10/10). I opted for unit tests rather than integration tests since it's difficult to reliably trigger the help text scenario in an end-to-end test (tsc searches parent directories for config files)

Added three unit tests to verify the help text detection behavior:

1. Detects tsc help text with 'The TypeScript Compiler - Version' marker
   - Throws clear error with configured tsconfig path
   - Provides actionable solutions

2. Detects help text with 'COMMON COMMANDS' marker alone
   - Ensures detection works with partial help output

3. Does not throw error for normal tsc error output
   - Verifies normal type errors are processed correctly

These tests directly verify the prepareResults() method's ability
to detect and handle tsc help text output, confirming the fix works
as intended without needing complex integration test setup.
@Ujjwaljain16 Ujjwaljain16 force-pushed the fix/typecheck-tsconfig-missing-error branch from 99b316b to 5ce857b Compare December 10, 2025 16:10
@Ujjwaljain16
Copy link
Contributor Author

Both CI failures (throws an error if typechecker process exists in typescript tests and boolean flag 100 should not crash CLI in config tests) appear to be pre-existing flaky tests unrelated to this PR. My changes only touch:

typechecker.ts (help text detection)
[typechecker.test.ts] (new unit tests - all passing)

The failing tests are in completely different areas (test runner error handling and coverage reporting).

@Ujjwaljain16
Copy link
Contributor Author

@sheremet-va waiting for yr review

…ommand

- Fixed race condition where stderr output was marking dataReceived=true
- This prevented proper error handling when command doesn't exist on Windows
- Added resolved flag to prevent double-rejection in promise
- Added winTimeout tracking for proper cleanup
- Now correctly throws 'Spawning typechecker failed' error on Windows

Fixes failing test: 'throws an error if typechecker process exists'
@Ujjwaljain16
Copy link
Contributor Author

The failing test "boolean flag 100 should not crash CLI" is unrelated to the typecheck changes in this PR. This PR only modifies typecheck/typechecker.ts for error handling, while the failure is in coverage threshold reporting. The test is expecting "ERROR: Coverage for functions" but it's not appearing in stderr.

All typecheck-related tests pass successfully, including the previously failing Windows CI test

@@ -0,0 +1,95 @@
import type { TestProject } from '../../../packages/vitest/src/node/project'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test doesn't actually test the functionality, it mocks everything. Please, add a test following the policy from AGENTS.md:

- **No mocking policy** - You must never mock anything in tests

Create a fixture or use runInlineTests to run tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “help text” scenario cannot be integration-tested because tsc always
searches parent directories for tsconfig.json files. Even with runInlineTests,
tsc still inherits a real working directory and climbs to the Vitest monorepo
root, where tsconfig files exist.

Because of this, tsc will never emit its help text in CI or in Vitest’s test
environment, and automated tests cannot reliably trigger this condition.
@sheremet-va

Copy link
Member

@sheremet-va sheremet-va Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't you just generate an invalid tsconfig file then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sheremet-va Thank you for the suggestion! I attempted the invalid tsconfig approach but ran into a technical constraint I'd like your input on.

Problem: tsc Help Text Trigger Conditions

After testing, I found that tsc only outputs help text under these conditions:

  • Invoked with zero arguments: tsc
  • Invoked with unrecognized flags: tsc --unknownFlag
  • Invoked with --help

However, Vitest's typechecker always invokes tsc with valid arguments:

// From typechecker.ts spawn()
const args = [
  '--noEmit',
  '--pretty', 'false',
  '--incremental',
  '--tsBuildInfoFile', '...',
  '-p', resolve(root, typecheck.tsconfig)
]
const child = x(typecheck.checker, args, {...})

Invalid tsconfig.json Attempts

Approach runInlineTests Config tsc Output Result
Syntactically invalid JSON 'tsconfig.json': '{ invalid }' N/A — Vite/esbuild fails first ❌ Build error before tsc runs
Empty object 'tsconfig.json': '{}' error TS18003: No inputs were found ❌ Error output, not help text
Missing compilerOptions 'tsconfig.json': '{"files":[]}' error TS18003: No inputs were found ❌ Error output, not help text

Root Cause

When tsc is invoked with -p <file> and the config file is structurally valid JSON (even if semantically incorrect), it enters normal compiler mode. In this mode, tsc emits specific diagnostic errors and never falls back to printing help text.

Help text is only produced when tsc itself is invoked with invalid or missing CLI arguments, which does not occur in Vitest’s invocation path.

Current Solution: Test Executable Stub
I implemented a temporary executable that outputs tsc help text:

// Creates cross-platform executable
const fakeTscPath = path.join(os.tmpdir(), `fake-tsc-${Date.now()}`)
fs.writeFileSync(fakeTscPath, '#!/usr/bin/env node\nconsole.log("Version 5.3.3");\n...')
fs.chmodSync(fakeTscPath, '755')

// Configure Vitest to use it
const config = `export default defineConfig({
  test: { typecheck: { checker: '${fakeTscPath}' } }
})`

Is there a specific tsconfig.json structure or tsc invocation pattern I'm missing that would trigger help text output when called with -p ?
Alternatively, is the test executable approach acceptable for this edge case, or would you prefer:

A different testing strategy you have in mind
Modifying how Vitest invokes tsc for this specific test scenario

- Removed mocked unit tests that violated no-mocking policy
- Added integration test using runVitest helper
- Tests non-existing typechecker command error handling
- Follows AGENTS.md testing guidelines
…ects when tsc outputs help text (indicating missing tsconfig.json) and provides a clear, actionable error message with solution steps.\n\nAdds integration test to verify the improved error handling.
@Ujjwaljain16
Copy link
Contributor Author

@sheremet-va Thank you for the feedback! I've addressed both points:

Changes Made

1. Static Imports
Replaced dynamic imports with static imports at the top of the file:

import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { createFile, runInlineTests } from '../../test-utils'

2. Using createFile Utility
Replaced manual file creation and cleanup with the createFile() utility:

createFile(fakeTscPath, scriptContent)

Test Results

✓ test/typecheck-error.test.ts (1 test) 417ms
  ✓ Typechecker Error Handling (1)
    ✓ throws helpful error when tsc outputs help text (missing config)

Test Files  1 passed (1)
Tests       1 passed (1)

@sheremet-va
Copy link
Member

Thank you!

@sheremet-va sheremet-va merged commit 7b10ab4 into vitest-dev:main Dec 23, 2025
14 of 16 checks passed
saschazepter pushed a commit to saschazepter/forgejo that referenced this pull request Feb 3, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/main/packages/coverage-v8#readme) ([source](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8)) | [`4.0.16` → `4.0.18`](https://renovatebot.com/diffs/npm/@vitest%2fcoverage-v8/4.0.16/4.0.18) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@vitest%2fcoverage-v8/4.0.18?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@vitest%2fcoverage-v8/4.0.16/4.0.18?slim=true) |
| [vitest](https://vitest.dev) ([source](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest)) | [`4.0.16` → `4.0.18`](https://renovatebot.com/diffs/npm/vitest/4.0.16/4.0.18) | ![age](https://developer.mend.io/api/mc/badges/age/npm/vitest/4.0.18?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/vitest/4.0.16/4.0.18?slim=true) |

---

### Release Notes

<details>
<summary>vitest-dev/vitest (@&#8203;vitest/coverage-v8)</summary>

### [`v4.0.18`](https://github.com/vitest-dev/vitest/releases/tag/v4.0.18)

[Compare Source](vitest-dev/vitest@v4.0.17...v4.0.18)

#####    🚀 Experimental Features

- **experimental**: Add `onModuleRunner` hook to `worker.init`  -  by [@&#8203;sheremet-va](https://github.com/sheremet-va) in [#&#8203;9286](vitest-dev/vitest#9286) [<samp>(ea837)</samp>](vitest-dev/vitest@ea837de7d)

#####    🐞 Bug Fixes

- Use `meta.url` in `createRequire`  -  by [@&#8203;sheremet-va](https://github.com/sheremet-va) in [#&#8203;9441](vitest-dev/vitest#9441) [<samp>(e0572)</samp>](vitest-dev/vitest@e057281ca)
- **browser**: Hide injected data-testid attributes  -  by [@&#8203;sheremet-va](https://github.com/sheremet-va) in [#&#8203;9503](vitest-dev/vitest#9503) [<samp>(f8989)</samp>](vitest-dev/vitest@f89899cd8)
- **ui**: Process artifact attachments when generating HTML reporter  -  by [@&#8203;macarie](https://github.com/macarie) in [#&#8203;9472](vitest-dev/vitest#9472) [<samp>(22543)</samp>](vitest-dev/vitest@225435647)

#####     [View changes on GitHub](vitest-dev/vitest@v4.0.17...v4.0.18)

### [`v4.0.17`](https://github.com/vitest-dev/vitest/releases/tag/v4.0.17)

[Compare Source](vitest-dev/vitest@v4.0.16...v4.0.17)

#####    🚀 Experimental Features

- Support openTelemetry for browser mode  -  by [@&#8203;hi-ogawa](https://github.com/hi-ogawa) in [#&#8203;9180](vitest-dev/vitest#9180) [<samp>(1ec3a)</samp>](vitest-dev/vitest@1ec3a8b68)
- Support TRACEPARENT and TRACESTATE environment variables for OpenTelemetry context propagation  -  by [@&#8203;Copilot](https://github.com/Copilot), **hi-ogawa** and [@&#8203;hi-ogawa](https://github.com/hi-ogawa) in [#&#8203;9295](vitest-dev/vitest#9295) [<samp>(876cb)</samp>](vitest-dev/vitest@876cb84c2)

#####    🐞 Bug Fixes

- Improve asymmetric matcher diff readability by unwrapping container matchers  -  by [@&#8203;Copilot](https://github.com/Copilot), **sheremet-va**, **hi-ogawa** and [@&#8203;hi-ogawa](https://github.com/hi-ogawa) in [#&#8203;9330](vitest-dev/vitest#9330) [<samp>(b2ec7)</samp>](vitest-dev/vitest@b2ec724a8)
- Improve runner error when importing outside of test context  -  by [@&#8203;sheremet-va](https://github.com/sheremet-va) in [#&#8203;9335](vitest-dev/vitest#9335) [<samp>(2dd3d)</samp>](vitest-dev/vitest@2dd3dd839)
- Replace crypto.randomUUID to allow insecure environments (fix [#&#8203;9](https://github.com/vitest-dev/vitest/issues/9)…  -  by [@&#8203;plusgut](https://github.com/plusgut) in [#&#8203;9339](vitest-dev/vitest#9339) and [#&#8203;9](vitest-dev/vitest#9) [<samp>(e6a3f)</samp>](vitest-dev/vitest@e6a3f8cc7)
- Handle null options in `addEventHandler` [#&#8203;9371](vitest-dev/vitest#9371)  -  by [@&#8203;ThibautMarechal](https://github.com/ThibautMarechal) in [#&#8203;9372](vitest-dev/vitest#9372) and [#&#8203;9371](vitest-dev/vitest#9371) [<samp>(40841)</samp>](vitest-dev/vitest@40841ff00)
- Typo in browser.provider error  -  by [@&#8203;deammer](https://github.com/deammer) in [#&#8203;9394](vitest-dev/vitest#9394) [<samp>(4b67f)</samp>](vitest-dev/vitest@4b67fc25a)
- **browser**:
  - Fix `process.env` and `import.meta.env` defines in inline project  -  by [@&#8203;hi-ogawa](https://github.com/hi-ogawa) in [#&#8203;9239](vitest-dev/vitest#9239) [<samp>(b70c9)</samp>](vitest-dev/vitest@b70c96121)
  - Fix upload File instance  -  by [@&#8203;hi-ogawa](https://github.com/hi-ogawa) in [#&#8203;9294](vitest-dev/vitest#9294) [<samp>(b6778)</samp>](vitest-dev/vitest@b67788c69)
  - Fix invalid project token for artifacts assets  -  by [@&#8203;hi-ogawa](https://github.com/hi-ogawa) in [#&#8203;9321](vitest-dev/vitest#9321) [<samp>(caa7d)</samp>](vitest-dev/vitest@caa7d73d4)
  - Log `ErrorEvent.message` when unhandled `ErrorEvent.error` is null  -  by [@&#8203;hi-ogawa](https://github.com/hi-ogawa) in [#&#8203;9322](vitest-dev/vitest#9322) [<samp>(5d84e)</samp>](vitest-dev/vitest@5d84eeb91)
  - Support `fileParallelism` on an instance  -  by [@&#8203;sheremet-va](https://github.com/sheremet-va) in [#&#8203;9328](vitest-dev/vitest#9328) [<samp>(15006)</samp>](vitest-dev/vitest@150065459)
- **coverage**:
  - Remove unnecessary `istanbul-lib-source-maps` usage  -  by [@&#8203;AriPerkkio](https://github.com/AriPerkkio) in [#&#8203;9344](vitest-dev/vitest#9344) [<samp>(b0940)</samp>](vitest-dev/vitest@b09405375)
  - Apply patch from [istanbuljs/istanbuljs#837](istanbuljs/istanbuljs#837)  -  by [@&#8203;AriPerkkio](https://github.com/AriPerkkio) and **sapphi-red** in [#&#8203;9413](vitest-dev/vitest#9413) and [#&#8203;837](vitest-dev/vitest#837) [<samp>(e05ce)</samp>](vitest-dev/vitest@e05cedbf4)
- **fsModuleCache**:
  - Don't store importers in cache  -  by [@&#8203;sheremet-va](https://github.com/sheremet-va) in [#&#8203;9422](vitest-dev/vitest#9422) [<samp>(75136)</samp>](vitest-dev/vitest@751364eec)
  - Add importers alongside importedModules  -  by [@&#8203;sheremet-va](https://github.com/sheremet-va) in [#&#8203;9423](vitest-dev/vitest#9423) [<samp>(59f92)</samp>](vitest-dev/vitest@59f92d403)
- **mocker**:
  - Fix mock transform with class  -  by [@&#8203;hi-ogawa](https://github.com/hi-ogawa) in [#&#8203;9421](vitest-dev/vitest#9421) [<samp>(d390e)</samp>](vitest-dev/vitest@d390eb527)
- **pool**:
  - Validate environment options when reusing the worker  -  by [@&#8203;sheremet-va](https://github.com/sheremet-va) in [#&#8203;9349](vitest-dev/vitest#9349) [<samp>(a8a88)</samp>](vitest-dev/vitest@a8a8836e3)
  - Handle worker start failures gracefully  -  by [@&#8203;AriPerkkio](https://github.com/AriPerkkio) in [#&#8203;9337](vitest-dev/vitest#9337) [<samp>(200da)</samp>](vitest-dev/vitest@200dadb32)
- **reporter**:
  - Report test module if it failed to run  -  by [@&#8203;sheremet-va](https://github.com/sheremet-va) in [#&#8203;9272](vitest-dev/vitest#9272) [<samp>(c7888)</samp>](vitest-dev/vitest@c78882985)
- **runner**:
  - Respect nested test.only within describe.only  -  by [@&#8203;Ujjwaljain16](https://github.com/Ujjwaljain16) in [#&#8203;9021](vitest-dev/vitest#9021) and [#&#8203;9213](vitest-dev/vitest#9213) [<samp>(55d5d)</samp>](vitest-dev/vitest@55d5dad69)
- **typecheck**:
  - Improve error message when tsc outputs help text  -  by [@&#8203;Ujjwaljain16](https://github.com/Ujjwaljain16) in [#&#8203;9214](vitest-dev/vitest#9214) [<samp>(7b10a)</samp>](vitest-dev/vitest@7b10ab4cd)
- **ui**:
  - Detect gzip by magic numbers instead of Content-Type header in html reporter  -  by [@&#8203;Copilot](https://github.com/Copilot), **hi-ogawa** and [@&#8203;hi-ogawa](https://github.com/hi-ogawa) in [#&#8203;9278](vitest-dev/vitest#9278) [<samp>(dd033)</samp>](vitest-dev/vitest@dd0331632)
- **webdriverio**:
  - Fall back to WebDriver Classic [#&#8203;9244](vitest-dev/vitest#9244)  -  by [@&#8203;JustasMonkev](https://github.com/JustasMonkev) in [#&#8203;9373](vitest-dev/vitest#9373) and [#&#8203;9244](vitest-dev/vitest#9244) [<samp>(c23dd)</samp>](vitest-dev/vitest@c23dd11bd)

#####     [View changes on GitHub](vitest-dev/vitest@v4.0.16...v4.0.17)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - Between 12:00 AM and 03:59 AM, on day 1 of the month ( * 0-3 1 * * ) (UTC), Automerge - Between 12:00 AM and 03:59 AM ( * 0-3 * * * ) (UTC).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi45My4xIiwidXBkYXRlZEluVmVyIjoiNDIuOTMuMSIsInRhcmdldEJyYW5jaCI6ImZvcmdlam8iLCJsYWJlbHMiOlsiZGVwZW5kZW5jeS11cGdyYWRlIiwidGVzdC9ub3QtbmVlZGVkIl19-->

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11121
Reviewed-by: Gusted <[email protected]>
Reviewed-by: Michael Kriese <[email protected]>
Co-authored-by: Renovate Bot <[email protected]>
Co-committed-by: Renovate Bot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Running vitest with --typecheck option throws error that prints out tsc --help if tsconfig.json is not available

2 participants