{"record":{"id":"1ae4155b98dede73","repo":"can1357/oh-my-pi","slug":"cannot-action-on-a-disposed-js-runtime","errorCode":null,"errorMessage":"Cannot ${action} on a disposed JS runtime","messagePattern":"Cannot (.+?) on a disposed JS runtime","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/eval/js/shared/runtime.ts","lineNumber":183,"sourceCode":" * Shared JS runtime for the eval worker and the browser tab worker. Owns the prelude,\n * helper bag, console bridge, and indirect-eval execution. Emits text/display/tool-call\n * back through `RuntimeHooks` that the embedder supplies — wire format is the embedder's\n * concern.\n */\nexport class JsRuntime {\n\t#globalOwner = Symbol(\"JsRuntime globals\");\n\t#ownedGlobalKeys = new Set<string>();\n\t#disposed = false;\n\t#runHookResolver = () => this.#als.getStore()?.hooks;\n\n\t#ownGlobal(key: string): void {\n\t\tif (this.#ownedGlobalKeys.has(key)) return;\n\t\tclaimGlobalKey(key, this.#globalOwner);\n\t\tthis.#ownedGlobalKeys.add(key);\n\t}\n\n\t#activateGlobals(action: string): void {\n\t\tif (this.#disposed) throw new Error(`Cannot ${action} on a disposed JS runtime`);\n\t\tactivateGlobalOwner(this.#globalOwner, this.#ownedGlobalKeys, action);\n\t}\n\n\treadonly helpers: HelperBundle;\n\t#cwd: string;\n\t#session: { cwd: string; sessionId: string };\n\treadonly sessionId: string;\n\t#env: Map<string, string>;\n\t#als = new AsyncLocalStorage<RunContext>();\n\t#moduleLoader: LocalModuleLoader;\n\t#localRoots: Record<string, string>;\n\n\tconstructor(opts: RuntimeOptions) {\n\t\tthis.#cwd = opts.initialCwd;\n\t\tthis.#session = { cwd: opts.initialCwd, sessionId: opts.sessionId };\n\t\tthis.sessionId = opts.sessionId;\n\t\tthis.#env = new Map();\n\t\tthis.#moduleLoader = new LocalModuleLoader(this.sessionId);","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/eval/js/shared/runtime.ts#L165-L201","documentation":"`#activateGlobals` is the guard run before any operation that needs the runtime's globals activated (setCwd, setRunScope, run). Once the JS runtime is disposed, its global-scope claim has been released, so any further use throws `Cannot <action> on a disposed JS runtime`. It prevents resurrecting global state after teardown and confusing cross-runtime ownership.","triggerScenarios":"Calling `runtime.run(...)`, `runtime.setCwd(...)`, or `runtime.setRunScope(...)` after `runtime.dispose()` (or after the worker/session teardown disposed it) — e.g. a queued run completing after termination, or reusing a cached runtime object across cell teardown.","commonSituations":"Race between an in-flight eval run and session kill; caching a runtime in user code and reusing it in a later cell; worker restart logic invoking setCwd on the old disposed instance.","solutions":["Create a fresh runtime (or new eval session) instead of reusing the disposed one.","Check disposal/liveness state before scheduling runs; drop references after dispose().","Serialize teardown: cancel pending runs before disposing, and guard callbacks with a disposed flag."],"exampleFix":"// before\nruntime.dispose();\nawait runtime.run(code); // throws\n// after\nif (isDisposed(runtime)) runtime = createRuntime();\nawait runtime.run(code);","handlingStrategy":"try-catch","validationCode":"if (runtimeDisposed) throw new Error(\"runtime already disposed; create a new one\");","typeGuard":"function isUsable(r: { [disposed]: boolean } | null | undefined): boolean {\n\treturn r != null && !r[\"disposed\"];\n}","tryCatchPattern":"try {\n\tawait runtime.run(code);\n} catch (err) {\n\tif (String(err?.message).includes(\"on a disposed JS runtime\")) {\n\t\truntime = createRuntime(); // recreate and retry once\n\t\tawait runtime.run(code);\n\t} else throw err;\n}","preventionTips":["Null out runtime references immediately after dispose().","Cancel or drain pending runs before disposing the session.","Add a liveness check before any queued/deferred run executes."],"tags":["lifecycle","runtime","disposed","sandbox"],"backgroundTag":"use-after-dispose","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}