Skip to content

Fix API server panic when opening a JS file that a tsconfig does not include - #65436

Draft
Ryan Cavanaugh (RyanCavanaugh) with Copilot wants to merge 3 commits into
mainfrom
copilot/fix-api-server-panic
Draft

Ryan Cavanaugh (RyanCavanaugh) with Copilot wants to merge 3 commits into
mainfrom
copilot/fix-api-server-panic

Conversation

Copilot AI commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Opening a .js/.mjs file through the API panics with a nil dereference in acquireConfigForFile → SyncMapEntry.ChangeIf when the nearest tsconfig includes no files. With the fix, the file opens in the inferred project, as it did in 7.0.2.

// tsconfig.json: {}   w.mjs: export const a = 1
api.createSnapshot({ openFiles: [cwd + "/w.mjs"] }); // panicked

Root cause

HandleAPIRequest looks up the config for each opened file twice in the same builder, with a cleanup in between:

  1. OpenFiles pass: acquires the tsconfig. There are no root files, so no project retains it, and API-opened files don't retain it either.
  2. cleanupConfiguredProjects: deletes the unretained entry from the builder's dirty.SyncMap.
  3. EnsureFiles pass: acquires the same tsconfig again. LoadOrStore returns (nil, false) for a key deleted earlier in the builder, and the caller dereferences nil.

A later updateSnapshot that opens another stray JS file hits the same path through LoadOrStore's base-map branch.

Changes

  • dirty.SyncMap.LoadOrStoreReplacingDeleted (new): like LoadOrStore, but if the key was deleted earlier in the builder, it stores the new value in that entry and returns it instead of nil.
    • LoadOrStore is unchanged: snapshotfs relies on its nil return to keep files deleted in a snapshot from being re-cached.
  • configFileRegistryBuilder: acquireConfigForFile, acquireConfigForProject and updateExtendingConfigs use the new method. A config that Cleanup removed earlier in the same snapshot is recreated and parsed again.

Tests

  • TestOpenFileNotIncludedByConfigOpensInInferredProject (internal/api):
    • covers w.mjs next to the tsconfig and src/nested/w.js two levels below it;
    • then calls updateSnapshot to open a second stray .cjs;
    • asserts every opened file lands in the inferred project.
  • TestSyncMapLoadOrStoreDeletedKey (internal/project/dirty): checks both lookup methods on deleted base keys and deleted added keys, and checks the finalized result.

Not addressed

findOrCreateProject → configuredProjects.LoadOrStore has the same "deleted earlier in this builder returns nil" behavior. Its callers treat nil as "not found", and this issue's steps don't reach it.

@typescript-automation typescript-automation Bot added Author: Team For Milestone Bug PRs that fix a bug with a specific milestone labels Nov 10, 2026
@typescript-automation typescript-automation Bot added For Uncommitted Bug PR for untriaged, rejected, closed or missing bug and removed For Milestone Bug PRs that fix a bug with a specific milestone labels Nov 10, 2026
Copilot AI and others added 2 commits November 10, 2026 23:53
…me snapshot

Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix API server panics in acquireConfigForFile for JS files Fix API server panic when opening a JS file that a tsconfig does not include Nov 11, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API server panics in acquireConfigForFile when opening a JS file a tsconfig does not include

2 participants