can1357/oh-my-pi · error · Error

Agent "${resolvedAgentId}" is already owned by another sessi

Error message

Agent "${resolvedAgentId}" is already owned by another session generation.

What it means

Agent identity is guarded by a global AgentLifecycleManager and an agent registry so only one live session generation can own a given agent id. When registerIfAvailable cannot claim the id (and no dead corpse could be reclaimed), construction aborts to prevent two sessions driving the same agent state.

Source

Thrown at packages/coding-agent/src/sdk.ts:3258

			options.expectedAgentRef === undefined
				? agentRegistry.register(registrationInput)
				: agentRegistry.registerIfAvailable(registrationInput, options.expectedAgentRef);
		if (!registeredAgentRef && options.expectedAgentRef === null) {
			// A fresh spawn collided with an existing id. If that id is held by a
			// provably-dead parked corpse — no live session, no reviver — reclaim it
			// so this new generation can take the id instead of failing forever at
			// construction. Without this, one such corpse (isolated-run park,
			// interrupted construction) poisons the id for the whole process (#8490).
			// The reclaim is gated by the lifecycle owner and only touches the
			// registry it manages; the corpse's transcript stays at history://.
			const stale = agentRegistry.get(resolvedAgentId);
			const lifecycle = AgentLifecycleManager.global();
			if (stale && lifecycle.manages(agentRegistry) && (await lifecycle.reclaimDeadCorpse(resolvedAgentId, stale))) {
				registeredAgentRef = agentRegistry.registerIfAvailable(registrationInput, null);
			}
		}
		if (!registeredAgentRef) {
			throw new Error(`Agent "${resolvedAgentId}" is already owned by another session generation.`);
		}
		// A reused parked ref remains parked until the new AgentSession is fully
		// constructed and attached. Startup failure therefore leaves it revivable.
		hasRegistered = options.expectedAgentRef === undefined || options.expectedAgentRef === null;

		// Partition the initial enabled set for the xd:// transport. Tool instances
		// remain in the canonical map; only presentation names move between layers.
		// Mounting requires both transport halves in the granted set (`read xd://`
		// discovers, `write xd://<tool>` executes); explicit-list sessions granted
		// `read` without `write` can use the device-only transport registered by
		// createTools without surfacing it when no device needs it.
		if (toolSession.xdev) {
			const topLevelToolNames: string[] = [];
			const mountedNames: string[] = [];
			for (const name of initialToolNames) {
				const tool = toolRegistry.get(name);
				const explicitlyRequested = explicitlyRequestedToolNameSet?.has(name) === true;
				if (tool && xdevReadAvailable && xdevWriteAvailable && !explicitlyRequested && isMountableUnderXdev(tool))

View on GitHub (pinned to 9690622007)

Solutions

  1. Close the other session that owns this agent, or use a different agent id
  2. Ensure the previous process actually exited (kill orphaned omp processes) so the corpse can be reclaimed
  3. Retry after the owning session is disposed; use expectedAgentRef when resuming intentionally

Example fix

// before
await createAgentSession({ agentId: "my-agent" }); // second concurrent call
// after
// run sequentially, or pick a unique id per session
await createAgentSession({ agentId: "my-agent-2" });
Defensive patterns

Strategy: retry

Validate before calling

const lifecycle = AgentLifecycleManager.global();
if (lifecycle.manages(registry) && lifecycle.isOwnedByLiveSession(agentId)) {
  throw new Error(`agent ${agentId} is already in use; pick another id or close the other session`);
}

Type guard

null

Try / catch

try {
  session = await createAgentSession({ agentId });
} catch (err) {
  if (err instanceof Error && err.message.includes("already owned by another session generation")) {
    await waitForAgentRelease(agentId); // poll until the other session disposes
    session = await createAgentSession({ agentId });
  } else throw err;
}

Prevention

When it happens

Trigger: createAgentSession for an agentId whose registry entry is held by another running session generation, with no stale/dead corpse to reclaim.

Common situations: Opening the same project/agent in two CLI instances; a previous session still alive holding the lock; orphaned process from a crash that the lifecycle manager has not classified as dead.

Related errors


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