{"record":{"id":"0872ef540e74e99e","repo":"microsoft/typescript-go","slug":"cannot-run-a-temporary-file-update-on-an-inactive","errorCode":null,"errorMessage":"Cannot run a temporary file update on an inactive snapshot","messagePattern":"Cannot run a temporary file update on an inactive snapshot","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"_packages/native-preview/src/api/async/api.ts","lineNumber":288,"sourceCode":"        }\r\n        // Release the latest snapshot's cache refs if still held\r\n        if (this.latestSnapshot) {\r\n            this.sourceFileCache.releaseSnapshot(this.latestSnapshot.id);\r\n            this.latestSnapshot = undefined;\r\n        }\r\n        await this.client.close();\r\n        this.sourceFileCache.clear();\r\n    }\r\n\r\n    clearSourceFileCache(): void {\r\n        this.sourceFileCache.clear();\r\n    }\r\n\r\n    async runWithTemporaryFileUpdate(baseSnapshot: Snapshot, file: DocumentIdentifier, newText: string, cb: (newSnapshot: Snapshot) => void | Promise<void>): Promise<void> {\r\n        await this.ensureInitialized();\r\n\r\n        if (!this.activeSnapshots.has(baseSnapshot) || baseSnapshot.isDisposed()) {\r\n            throw new Error(\"Cannot run a temporary file update on an inactive snapshot\");\r\n        }\r\n        const data = await this.client.apiRequest<UpdateSnapshotResponse>(\"updateTemporarySnapshot\", { snapshot: baseSnapshot.id, file, newText });\r\n\r\n        // Retain cached source files from the base snapshot for files unchanged by\r\n        // the temporary update. The temporary snapshot is not the latest snapshot, so\r\n        // we never release the latest snapshot's cache here.\r\n        this.sourceFileCache.retainForSnapshot(data.snapshot, baseSnapshot.id, data.changes);\r\n\r\n        const snapshot = new Snapshot(\r\n            data,\r\n            this.client,\r\n            this.sourceFileCache,\r\n            this.toPath!,\r\n            () => {\r\n                this.activeSnapshots.delete(snapshot);\r\n                this.sourceFileCache.releaseSnapshot(snapshot.id);\r\n            },\r\n        );\r","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/_packages/native-preview/src/api/async/api.ts#L270-L306","documentation":"Thrown by API.runWithTemporaryFileUpdate when baseSnapshot is no longer in the API's activeSnapshots set or reports isDisposed(). Snapshots leave the active set via snapshot.dispose() - explicit calls, API.close() disposing every active snapshot, or temporary snapshots disposed automatically in the runWithTemporaryFileUpdate finally block. The guard prevents sending updateTemporarySnapshot for a server-side snapshot that has already been released.","triggerScenarios":"Reusing a temporary snapshot after its callback completed (auto-disposed in finally); passing a snapshot explicitly disposed earlier; calling after API.close(); passing a Snapshot obtained from a different API instance (never in this instance's activeSnapshots set).","commonSituations":"Caching a Snapshot across editor changes and then attempting a quick-fix/organize-imports temporary update on the stale one; nesting temporary updates where the outer callback's snapshot is used after await points that disposed it; integration tests that keep one snapshot for the whole run.","solutions":["Always base temporary updates on the freshest snapshot: call updateSnapshot(...) and use its return value immediately","Check baseSnapshot.isDisposed() (public API) before calling, and stop caching snapshots across updates","Do not use snapshots after API.close() or after their dispose() - reacquire from the API","Only pass snapshots created by the same API instance"],"exampleFix":"// before\nconst snap = await api.updateSnapshot(); // ... later, after another update/dispose\nawait api.runWithTemporaryFileUpdate(snap, file, text, cb); // throws\n\n// after\nconst snap = await api.updateSnapshot(); // freshest state, same tick\nif (snap.isDisposed()) throw new Error('snapshot went stale');\nawait api.runWithTemporaryFileUpdate(snap, file, text, cb);","handlingStrategy":"validation","validationCode":"// Public guard: only base updates on fresh, undisposed snapshots\nif (baseSnapshot.isDisposed()) {\n    throw new Error('base snapshot is disposed - call updateSnapshot() to get a fresh one');\n}\nawait api.runWithTemporaryFileUpdate(baseSnapshot, file, newText, cb);","typeGuard":null,"tryCatchPattern":"try {\n    await api.runWithTemporaryFileUpdate(snap, file, text, cb);\n} catch (e) {\n    if (e instanceof Error && e.message.includes('inactive snapshot')) {\n        snap = await api.updateSnapshot(); // refresh and retry once\n        await api.runWithTemporaryFileUpdate(snap, file, text, cb);\n    } else throw e;\n}","preventionTips":["Never cache snapshots; always derive from the latest updateSnapshot result","Copy needed data out of runWithTemporaryFileUpdate's callback before it returns","Use one API instance per session and never mix snapshots across instances"],"tags":["api","snapshot","lifecycle","native-preview","validation"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}