can1357/oh-my-pi · warning

Session disposed before launch completion delivery

Error message

Session disposed before launch completion delivery

What it means

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.

Source

Thrown at packages/coding-agent/src/tools/hub/launch.ts:75

	session: ToolSession,
	client: DaemonBrokerClient,
	owner: string,
): CompletionLease | undefined {
	if (!session.queueLaunchCompletion) return undefined;
	let clients = completionRegistrations.get(session);
	if (!clients) {
		clients = new Map();
		completionRegistrations.set(session, clients);
	}
	let owners = clients.get(client);
	if (!owners) {
		owners = new Map();
		clients.set(client, owners);
	}
	let registration = owners.get(owner);
	if (!registration) {
		const unregister = client.onCompletion(owner, notification => {
			if (session.isDisposed?.()) throw new Error("Session disposed before launch completion delivery");
			const delivery = session.queueLaunchCompletion?.(notification);
			if (!delivery) throw new Error("Session cannot accept launch completion delivery");
			return delivery;
		});
		let unregisterDispose: (() => void) | void;
		let unregisterSessionChange: (() => void) | void;
		const cleanup = (preservePending = false): void => {
			if (!registration?.active) return;
			registration.active = false;
			unregister({ preservePending });
			unregisterDispose?.();
			unregisterSessionChange?.();
			owners.delete(owner);
			if (owners.size === 0) clients.delete(client);
			if (clients.size === 0) completionRegistrations.delete(session);
		};
		registration = { inFlight: 0, retained: false, active: true, cleanup };
		owners.set(owner, registration);

View on GitHub (pinned to 9690622007)

Solutions

  1. Ignore if you intentionally aborted the session — the error reflects the abort racing completion and is expected.
  2. Retry the launch in a fresh, live session.
  3. 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.
Defensive patterns

Strategy: try-catch

Validate before calling

// Before disposing the session, ensure no launch is pending:
if (session.isDisposed?.()) throw new Error("cannot launch: session already disposed");

Try / catch

try {
  await launchTool.run({ op: "start", name, application, ready });
} catch (err) {
  if (err instanceof Error && err.message === "Session disposed before launch completion delivery") {
    // session was aborted mid-launch; retry in a live session or ignore on abort
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/210f7bd204f1123f. Report an issue: GitHub.