microsoft/typescript-go · error
Snapshot is disposed
Error message
Snapshot is disposed
What it means
Snapshot.ensureNotDisposed guards every operation on a Snapshot object. Once dispose() runs — explicitly, via API.close(), or because the snapshot was superseded — the object releases its server-side resources (apiRequest('release')) and refuses further use by throwing 'Snapshot is disposed'. This is a use-after-free guard for the RPC-backed snapshot lifecycle.
Source
Thrown at _packages/native-preview/src/api/sync/api.ts:445
dispose(): void {
if (this.disposed) return;
this.disposed = true;
for (const project of this.projectMap.values()) {
project.dispose();
}
this.projectMap.clear();
this.snapshotRegistry.clear();
this.onDispose();
this.client.apiRequest("release", { snapshot: this.id });
}
isDisposed(): boolean {
return this.disposed;
}
private ensureNotDisposed(): void {
if (this.disposed) {
throw new Error("Snapshot is disposed");
}
}
}
class SnapshotObjectRegistry {
private readonly symbols: Map<number, Symbol> = new Map();
private readonly client: Client;
private readonly snapshotId: number;
private readonly resolveProject: (projectId: Path) => Project | undefined;
constructor(client: Client, snapshotId: number, resolveProject: (projectId: Path) => Project | undefined) {
this.client = client;
this.snapshotId = snapshotId;
this.resolveProject = resolveProject;
}
/** Resolve a project id (a config file path) to its Project within this snapshot. */
getProject(projectId: Path): Project | undefined {
View on GitHub (pinned to 1bcfa18d79)
Solutions
- Call snapshot.isDisposed() before each use and refetch a current snapshot when disposed
- Treat snapshots as short-lived: acquire, query, dispose — never cache across sync cycles
- Audit dispose() call sites so only the snapshot's owner disposes it
Example fix
// before const info = snapshot.getQuickInfo(pos); // throws if disposed // after if (snapshot.isDisposed()) snapshot = api.getProjectSnapshot(project); const info = snapshot.getQuickInfo(pos);
Defensive patterns
Strategy: validation
Validate before calling
if (snapshot.isDisposed()) { snapshot = api.getProjectSnapshot("tsconfig.json"); } Try / catch
try { result = snapshot.someQuery(pos); } catch (e) { if ((e as Error).message === "Snapshot is disposed") { snapshot = refreshSnapshot(); result = snapshot.someQuery(pos); } else throw e; } Prevention
- Treat snapshots as ephemeral: acquire, query, drop
- Gate every use with isDisposed()
- Coordinate disposal ownership so only one path disposes a snapshot
When it happens
Trigger: Calling any method on a Snapshot after snapshot.dispose(); calling methods on the latest snapshot after api.close() disposed all snapshots; using a snapshot captured before an updateFiles/sync cycle replaced it.
Common situations: Long-lived editor integrations caching snapshots across document changes; error paths that dispose then continue processing; concurrent handlers sharing a Snapshot without coordinating disposal.
Related errors
- Cannot run a temporary file update on an inactive snapshot
- Cannot run a temporary file update on an inactive snapshot
- Snapshot is disposed
- SyncRpcChannel is closed
- %w: symbol handle %d not found in snapshot registry
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/5c9b0df0e34c3d27.
Report an issue: GitHub.