microsoft/typescript-go · error

Cannot run a temporary file update on an inactive snapshot

Error message

Cannot run a temporary file update on an inactive snapshot

What it means

runWithTemporaryFileUpdate applies a text edit to an existing Snapshot and returns a temporary Snapshot for queries like 'what would quickinfo look like with this edit'. The base snapshot must be live: still registered in the API's activeSnapshots set and not disposed. Using a stale, disposed, or foreign snapshot would compute results against server state that no longer exists, so the API throws up front.

Source

Thrown at _packages/native-preview/src/api/sync/api.ts:296

        }
        // Release the latest snapshot's cache refs if still held
        if (this.latestSnapshot) {
            this.sourceFileCache.releaseSnapshot(this.latestSnapshot.id);
            this.latestSnapshot = undefined;
        }
        this.client.close();
        this.sourceFileCache.clear();
    }

    clearSourceFileCache(): void {
        this.sourceFileCache.clear();
    }

    runWithTemporaryFileUpdate(baseSnapshot: Snapshot, file: DocumentIdentifier, newText: string, cb: (newSnapshot: Snapshot) => void): void {
        this.ensureInitialized();

        if (!this.activeSnapshots.has(baseSnapshot) || baseSnapshot.isDisposed()) {
            throw new Error("Cannot run a temporary file update on an inactive snapshot");
        }
        const data = this.client.apiRequest<UpdateSnapshotResponse>("updateTemporarySnapshot", { snapshot: baseSnapshot.id, file, newText });

        // Retain cached source files from the base snapshot for files unchanged by
        // the temporary update. The temporary snapshot is not the latest snapshot, so
        // we never release the latest snapshot's cache here.
        this.sourceFileCache.retainForSnapshot(data.snapshot, baseSnapshot.id, data.changes);

        const snapshot = new Snapshot(
            data,
            this.client,
            this.sourceFileCache,
            this.toPath!,
            () => {
                this.activeSnapshots.delete(snapshot);
                this.sourceFileCache.releaseSnapshot(snapshot.id);
            },
        );

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Always derive temporary updates from the most recent snapshot returned by the API
  2. Check snapshot.isDisposed() before use and re-acquire a fresh snapshot if true
  3. Ensure only one owner disposes a snapshot; don't reuse snapshots across API.close() boundaries

Example fix

// before
const snap = api.getProjectSnapshot(p);
/* ... later, after dispose */
api.runWithTemporaryFileUpdate(snap, file, newText, cb); // throws

// after
if (snap.isDisposed()) throw new Error("stale snapshot");
api.runWithTemporaryFileUpdate(snap, file, newText, cb);
Defensive patterns

Strategy: validation

Validate before calling

const canRunTempUpdate = (api: API, snap: Snapshot) =>
  !snap.isDisposed() && /* snap obtained from this api and not yet replaced */ true;

Try / catch

try { api.runWithTemporaryFileUpdate(snap, file, text, cb); } catch (e) { if ((e as Error).message.includes("inactive snapshot")) { snap = api.getProjectSnapshot(cfg); api.runWithTemporaryFileUpdate(snap, file, text, cb); } else throw e; }

Prevention

When it happens

Trigger: Calling api.runWithTemporaryFileUpdate(snapshot, ...) after snapshot.dispose(); after api.close() (which clears activeSnapshots); passing a Snapshot obtained from a different API instance; holding a snapshot across project reloads until the server released it.

Common situations: Caching snapshots for reuse in language services; async races where one code path disposes a snapshot while another still uses it; editor integration keeping an old snapshot after a didChange cycle invalidated it.

Related errors


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/b3c42f478fd973ae. Report an issue: GitHub.