{"record":{"id":"210f7bd204f1123f","repo":"can1357/oh-my-pi","slug":"session-disposed-before-launch-completion-delivery","errorCode":null,"errorMessage":"Session disposed before launch completion delivery","messagePattern":"Session disposed before launch completion delivery","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/coding-agent/src/tools/hub/launch.ts","lineNumber":75,"sourceCode":"\tsession: ToolSession,\n\tclient: DaemonBrokerClient,\n\towner: string,\n): CompletionLease | undefined {\n\tif (!session.queueLaunchCompletion) return undefined;\n\tlet clients = completionRegistrations.get(session);\n\tif (!clients) {\n\t\tclients = new Map();\n\t\tcompletionRegistrations.set(session, clients);\n\t}\n\tlet owners = clients.get(client);\n\tif (!owners) {\n\t\towners = new Map();\n\t\tclients.set(client, owners);\n\t}\n\tlet registration = owners.get(owner);\n\tif (!registration) {\n\t\tconst unregister = client.onCompletion(owner, notification => {\n\t\t\tif (session.isDisposed?.()) throw new Error(\"Session disposed before launch completion delivery\");\n\t\t\tconst delivery = session.queueLaunchCompletion?.(notification);\n\t\t\tif (!delivery) throw new Error(\"Session cannot accept launch completion delivery\");\n\t\t\treturn delivery;\n\t\t});\n\t\tlet unregisterDispose: (() => void) | void;\n\t\tlet unregisterSessionChange: (() => void) | void;\n\t\tconst cleanup = (preservePending = false): void => {\n\t\t\tif (!registration?.active) return;\n\t\t\tregistration.active = false;\n\t\t\tunregister({ preservePending });\n\t\t\tunregisterDispose?.();\n\t\t\tunregisterSessionChange?.();\n\t\t\towners.delete(owner);\n\t\t\tif (owners.size === 0) clients.delete(client);\n\t\t\tif (clients.size === 0) completionRegistrations.delete(session);\n\t\t};\n\t\tregistration = { inFlight: 0, retained: false, active: true, cleanup };\n\t\towners.set(owner, registration);","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/hub/launch.ts#L57-L93","documentation":"The launch tool registers a completion sink that delivers daemon-launch completion notifications to the session. If the notification callback fires after the session has been disposed, it throws this error because a dead session can no longer receive the completion delivery. This is an internal lifecycle guard, not a user-input validation error.","triggerScenarios":"A launch completion notification arrives via client.onCompletion after `session.isDisposed()` returns true — i.e. the session was closed/cancelled while a daemon start was still in flight.","commonSituations":"User aborted or exited the agent session while a launch tool call was awaiting readiness; a timeout/cancellation disposed the session concurrently with the daemon finishing; long readiness waits (ready.log polling) racing session shutdown.","solutions":["Ignore if you intentionally aborted the session — the error reflects the abort racing completion and is expected.","Retry the launch in a fresh, live session.","Reduce the launch readiness wait (ready.log/ready.port) so completion lands before the session is disposed, or avoid disposing the session while a launch is pending."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before disposing the session, ensure no launch is pending:\nif (session.isDisposed?.()) throw new Error(\"cannot launch: session already disposed\");","typeGuard":null,"tryCatchPattern":"try {\n  await launchTool.run({ op: \"start\", name, application, ready });\n} catch (err) {\n  if (err instanceof Error && err.message === \"Session disposed before launch completion delivery\") {\n    // session was aborted mid-launch; retry in a live session or ignore on abort\n  } else throw err;\n}","preventionTips":["Don't dispose the session while a launch with readiness waits is pending.","Keep readiness timeouts shorter than session lifetime expectations.","Treat this error as expected noise when aborting mid-launch."],"tags":["lifecycle","race-condition","session-disposed"],"backgroundTag":"session-disposed-delivery","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}