can1357/oh-my-pi · error · ToolError

Async bash execution is disabled. Enable async.enabled to us

Error message

Async bash execution is disabled. Enable async.enabled to use async mode.

What it means

The bash tool only permits async execution when the session setting async.enabled is true. If the caller passes async=true while the setting is off, the tool rejects the call before doing any work. This keeps opt-in background execution from running in configurations that haven't enabled it.

Source

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

		ctx?: AgentToolContext,
	): Promise<AgentToolResult<BashToolDetails>> {
		let command = rawCommand;
		const env = normalizeBashEnv(rawEnv);

		// Extract a leading `cd <path> && ...` into cwd when the model ignores the
		// cwd parameter. The scanner captures only a single path token and defers
		// to the shell for anything else (redirects, extra args, shell expansion),
		// so it never absorbs shell syntax like `cd /tmp 2>/dev/null && ...` into
		// the structured cwd. Constrained to a top-level `&&` on the first line.
		if (!cwd) {
			const cd = extractLeadingCdTarget(command);
			if (cd) {
				cwd = cd.path;
				command = cd.rest;
			}
		}
		if (asyncRequested && !this.#asyncEnabled) {
			throw new ToolError("Async bash execution is disabled. Enable async.enabled to use async mode.");
		}

		// Check both the original command and the cwd-normalized command so
		// leading `cd ... &&` wrappers do not hide either shell-navigation rules
		// or the dedicated-tool command that follows the directory change.
		if (this.session.settings.get("bashInterceptor.enabled")) {
			const rules = this.session.settings.getBashInterceptorRules();
			const commandsToCheck = rawCommand === command ? [command] : [rawCommand, command];
			for (const commandToCheck of commandsToCheck) {
				const interception = checkBashInterception(commandToCheck, ctx?.toolNames ?? [], rules, rawCommand);
				if (interception.block) {
					throw new ToolError(interception.message ?? "Command blocked");
				}
			}
		}

		const internalUrlOptions: InternalUrlExpansionOptions = {
			skills: this.session.skills ?? [],

View on GitHub (pinned to 9690622007)

Solutions

  1. Enable the setting: set "async": { "enabled": true } in the omp settings file.
  2. Or remove async=true from the tool call and run the command in the foreground.
  3. Check which settings file applies (project vs user) with `omp settings` / the config docs if you believe it is already enabled.

Example fix

// before: omp.json
{ "tools": { "maxTimeout": 600 } }

// after: opt into async bash
{ "async": { "enabled": true }, "tools": { "maxTimeout": 600 } }
Defensive patterns

Strategy: validation

Validate before calling

if (wantAsync && !session.settings.get("async.enabled")) {
  // run foreground instead or tell the user to enable async.enabled
}
await bash.execute(id, { command, async: session.settings.get("async.enabled") });

Try / catch

try {
  await bash.execute(id, { command, async: true });
} catch (e) {
  if (e instanceof ToolError && e.message.includes("async.enabled")) {
    return bash.execute(id, { command }); // foreground fallback
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling bash with async=true (or relying on auto-backgrounding, which requests async internally) while the `async.enabled` setting is false/unset in omp.json or the session's settings.

Common situations: Users upgrading from versions where async defaulted differently; prompts that instruct the agent to 'run this in the background' on installs where the feature was never enabled; shared config files that omit the setting.

Related errors


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