can1357/oh-my-pi · error · ToolError

Unknown vibe session "${id}".${roster.length > 0 ? ` Active

Error message

Unknown vibe session "${id}".${roster.length > 0 ? ` Active sessions: ${roster.join(", ")}` : " No sessions — spawn one with vibe_spawn."}

What it means

#record looks up a vibe worker by scope key (owner + parent session + id). If no record exists or the record belongs to a different scope, it throws, appending the roster of active session ids in the current scope — or a hint to spawn one with vibe_spawn when none exist. This is a lookup failure: the requested id was never spawned in this scope, or has terminated.

Source

Thrown at packages/coding-agent/src/vibe/runtime.ts:542

			}
			sessionManager.appendModeChange?.("none");
		});
		for (const record of pending) record.terminalPersisted = true;
	}

	#manager(session: ToolSession): AsyncJobManager {
		const manager = session.asyncJobManager;
		if (!manager) {
			throw new ToolError("Vibe sessions require async execution (no background job manager is available).");
		}
		return manager;
	}

	#record(scope: VibeOwnerScope, id: string): VibeRecord {
		const record = this.#records.get(scopeKey(scope, id.trim()));
		if (!record || !matchesScope(record, scope)) {
			const roster = this.#listIds(scope);
			throw new ToolError(
				`Unknown vibe session "${id}".${roster.length > 0 ? ` Active sessions: ${roster.join(", ")}` : " No sessions — spawn one with vibe_spawn."}`,
			);
		}
		return record;
	}

	#registeredAgent(record: VibeRecord): AgentRef | undefined {
		const ref = AgentRegistry.global().get(record.id);
		if (ref?.kind !== "sub" || ref.parentId !== record.ownerId) return undefined;
		if (record.childSessionFile && ref.sessionFile !== record.childSessionFile) return undefined;
		return ref;
	}

	#listIds(scope: VibeOwnerScope): string[] {
		const ids: string[] = [];
		for (const record of this.#records.values()) {
			if (matchesScope(record, scope) && record.state !== "dead") ids.push(record.id);
		}

View on GitHub (pinned to 9690622007)

Solutions

  1. List active vibe sessions first and use an id from the roster.
  2. Re-spawn with vibe_spawn if the session terminated or the process restarted.
  3. Ensure the call runs in the same parent session and agent scope that spawned the worker (ownerId/parentSessionId must match).

Example fix

// before
await vibe.send(session, "worker-7", "continue"); // stale/unknown id
// after
const { sessions } = await vibe.list(session);
const target = sessions.find(s => s.state === "running");
if (target) await vibe.send(session, target.id, "continue");
Defensive patterns

Strategy: try-catch

Validate before calling

const roster = await vibe.list(session);
if (!roster.sessions.some(s => s.id === id)) {
  throw new Error(`"${id}" is not an active vibe session; pick one of: ${roster.sessions.map(s => s.id).join(", ")}`);
}

Try / catch

try {
  await vibe.send(session, id, msg);
} catch (err) {
  if (err instanceof ToolError && err.message.startsWith("Unknown vibe session")) {
    const { sessions } = await vibe.list(session);
    const target = sessions.find(s => s.state === "running");
    if (target) await vibe.send(session, target.id, msg);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling vibe send/status/kill/watch (→ #record or watched) with an id that is not an active worker in the current owner scope: typo'd id, worker already exited and reaped, or the call issued from a different agent/session scope than the spawn.

Common situations: Referencing a worker after it finished and its record was rebuilt to terminal state under a different scope; stale id cached in agent memory after restart (records are rebuilt from persisted events and live jobs are process-local); calling from a subagent whose ownerId differs from the spawner.

Related errors


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