can1357/oh-my-pi · error · ToolError

Background job manager unavailable for this session.

Error message

Background job manager unavailable for this session.

What it means

BashTool's #startManagedBashJob requires the session's AsyncJobManager to register and track background jobs. When session.asyncJobManager is undefined, the tool cannot create a managed job and throws this ToolError immediately instead of starting the background command. It guards the auto-backgrounding path where the command would otherwise silently lose tracking, output delivery, and cancellation.

Source

Thrown at packages/coding-agent/src/tools/bash.ts:816

	#extractTextResult(result: AgentToolResult<BashToolDetails>): string {
		return result.content.find(block => block.type === "text")?.text ?? "";
	}

	#startManagedBashJob(options: {
		command: string;
		commandCwd: string;
		timeoutMs: number | undefined;
		timeoutSec: number | undefined;
		requestedTimeoutSec?: number;
		notices?: readonly string[];

		resolvedEnv?: Record<string, string>;
		onUpdate?: AgentToolUpdateCallback<BashToolDetails>;
		forwardUpdates: boolean;
	}): ManagedBashJobHandle {
		const manager = this.session.asyncJobManager;
		if (!manager) {
			throw new ToolError("Background job manager unavailable for this session.");
		}

		const label = options.command.length > 120 ? `${options.command.slice(0, 117)}...` : options.command;
		let latestText = "";
		let forwardUpdates = options.forwardUpdates;
		const completion = Promise.withResolvers<ManagedBashJobCompletion>();

		const jobId = manager.register(
			"bash",
			label,
			async ({ jobId, signal: runSignal, reportProgress }) => {
				const { path: artifactPath, id: artifactId } = (await this.session.allocateOutputArtifact?.("bash")) ?? {};
				const tailBuffer = new TailBuffer(DEFAULT_MAX_BYTES);
				const wallTimeStart = performance.now();
				try {
					const result = await executeBash(options.command, {
						cwd: options.commandCwd,
						sessionKey: `${this.session.getSessionId?.() ?? ""}:async:${jobId}`,

View on GitHub (pinned to 9690622007)

Solutions

  1. Construct the session with an AsyncJobManager attached (session.asyncJobManager set) before invoking the bash tool.
  2. If background execution is not desired, don't request it: pass async=false and disable autoBackground in settings so the foreground path runs.
  3. Check session capabilities up front and surface a clear 'background not supported in this host' message instead of reaching the tool call.

Example fix

// before: minimal session without job manager
const session = createSession({ /* no asyncJobManager */ });
await bash.execute(id, { command: "npm test", async: true });

// after: wire the job manager
const session = createSession({ asyncJobManager: new AsyncJobManager() });
await bash.execute(id, { command: "npm test", async: true });
Defensive patterns

Strategy: validation

Validate before calling

if (!session.asyncJobManager) {
  throw new Error("This session has no async job manager; background bash is unavailable.");
}
await bash.execute(id, { command, async: true });

Try / catch

try {
  await bash.execute(id, { command, async: true });
} catch (e) {
  if (e instanceof ToolError && e.message.includes("job manager unavailable")) {
    // fall back to foreground execution
    return bash.execute(id, { command });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the bash tool with async=true (or a command that triggers auto-backgrounding) on a session constructed without an AsyncJobManager — e.g. embedding the SDK with a minimal session factory, or a session mode that never instantiates the job manager.

Common situations: SDK/custom-session embedders omitting the async job manager wiring; headless or restricted runtimes where background jobs are intentionally disabled; sessions created by third-party harnesses predating the async job manager feature.

Related errors


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