can1357/oh-my-pi · error · ToolError

Vibe sessions require async execution (no background job man

Error message

Vibe sessions require async execution (no background job manager is available).

What it means

Vibe workers run as background turn jobs, so the registry requires session.asyncJobManager. #manager() throws when the session has no async job manager — vibe cannot schedule, queue, or track worker turns. Any spawn or turn operation on such a session fails before any worker is created.

Source

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

			throw new ToolError("Vibe mode exit requires atomic parent-session persistence.");
		}
		await appendEntriesAtomically.call(sessionManager, () => {
			for (const record of persistedPending) {
				sessionManager.appendCustomEntry(VIBE_LIFECYCLE_CUSTOM_TYPE, {
					...this.#eventBase(record),
					action: "tombstone",
					reason: "mode-exit",
				});
			}
			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;

View on GitHub (pinned to 9690622007)

Solutions

  1. Wire an AsyncJobManager into the session (session.asyncJobManager) before using vibe mode.
  2. Run vibe mode in the standard CLI/TUI runtime where the async job manager is always installed.
  3. If embedding, initialize background-job support on the session during setup.

Example fix

// before
const session = createSession({ asyncJobManager: undefined });
await vibe.spawn(session, { cli: "fast", prompt }); // throws
// after
const session = createSession({ asyncJobManager: new AsyncJobManager() });
await vibe.spawn(session, { cli: "fast", prompt });
Defensive patterns

Strategy: validation

Validate before calling

if (!session.asyncJobManager) {
  throw new Error("Vibe requires a session with async job support; enable background jobs");
}

Type guard

function supportsAsyncJobs(s: ToolSession): boolean {
  return !!s.asyncJobManager;
}

Try / catch

try {
  await vibe.spawn(session, { cli, prompt });
} catch (err) {
  if (err instanceof ToolError && err.message.includes("async execution")) {
    throw new Error("Enable background job support on this session to use vibe mode");
  } else throw err;
}

Prevention

When it happens

Trigger: Calling vibe spawn or a worker-turn operation (→ #spawnLocked/#manager) on a ToolSession whose asyncJobManager is undefined — e.g. sessions created without background-job support, restricted/embedded runtimes, or sessions configured for synchronous-only execution.

Common situations: SDK embeddings that omit the async job manager wiring; headless/one-shot runs where background jobs are disabled; tests constructing minimal ToolSession doubles.

Related errors


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