Stale TypeScript diagnostics after Edit/Write — race condition with TS language server

Resolved 💬 3 comments Opened Feb 9, 2026 by Onzi12 Closed Feb 13, 2026

Problem

After Edit or Write tool calls, the <new-diagnostics> tags frequently contain stale TypeScript errors from the pre-edit file state. This is because the TS language server (tsserver) hasn't finished re-analyzing the file by the time Claude Code collects diagnostics.

This causes Claude to:

  • "Fix" errors that don't actually exist
  • Waste turns investigating phantom type errors
  • Sometimes introduce new bugs by reverting correct changes

Reproduction

Rapid sequential edits on a complex TypeScript file reliably trigger this:

  1. Edit 1: Introduce a type error (e.g., change private readonly DEFAULT_CHUNK_SIZE = 100 to = 'not-a-number')
  • Result: No diagnostics reported (tsserver hasn't caught up yet)
  1. Edit 2: Fix it back to = 100
  • Result: Stale diagnostics appear from the broken intermediate state (e.g., Operator '+=' cannot be applied to types 'number' and 'string | number')
  1. Running npx tsc --noEmit confirms zero actual errors — the diagnostics were phantom

Confirmed across 29 incidents in 17 sessions in a single project.

Root Cause

Classic race condition:

Edit/Write completes → Claude Code reads diagnostics → tsserver finishes re-analyzing
                        ↑ stale data here            ↑ fresh data arrives too late

The TS language server uses file watchers to detect changes, then re-parses, resolves imports, and type-checks. For complex files with deep import chains, this takes 200–800ms. Claude Code collects diagnostics immediately after the edit tool returns, before tsserver completes.

Workaround (confirmed working)

A PostToolUse hook that adds a 1-second delay after Edit/Write, giving tsserver time to catch up:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "sleep 1",
            "statusMessage": "Letting TS language server catch up to prevent stale diagnostics"
          }
        ]
      }
    ]
  }
}

Before hook: Edit 2 (fix) reports stale errors from Edit 1 (break)
After hook: Edit 2 (fix) correctly reports zero errors

Suggested Platform Fix

Rather than requiring users to add a sleep hook, Claude Code could:

  1. Wait for tsserver to settle before collecting diagnostics (e.g., wait for the semanticDiag response after the file change event)
  2. Debounce diagnostic collection — if an edit just happened, delay collection by ~1s
  3. Mark diagnostics as potentially stale when they're collected within N ms of an Edit/Write, so the model knows not to trust them blindly
  4. Skip diagnostic collection entirely after Edit/Write and let the model explicitly request them if needed

Option 1 is the most correct. Option 3 is the lowest-effort improvement.

Environment

  • Claude Code (CLI)
  • TypeScript project with ~60 source files
  • macOS (Darwin 25.2.0)

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗