can1357/oh-my-pi · error · ToolError

Working directory does not exist: ${commandCwd}

Error message

Working directory does not exist: ${commandCwd}

What it means

Before running a command the tool stats the resolved working directory (the cwd parameter resolved against the session cwd, or the session cwd itself). If stat fails with ENOENT the path does not exist, so there is nowhere to run the command and the tool throws this ToolError. Non-ENOENT stat errors are re-thrown unchanged.

Source

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

		// Resolve protocol URLs (skill://, agent://, etc.) in extracted cwd.
		if (cwd?.includes("://") || cwd?.includes("local:/")) {
			cwd = await expandInternalUrls(cwd, { ...internalUrlOptions, noEscape: true });
		}

		// Best-effort cache invalidation: drop github-cache rows for any issue/PR
		// number touched by a mutating `gh` subcommand inside this bash call so
		// subsequent issue:// / pr:// reads pick up the post-mutation state
		// instead of the cached pre-mutation snapshot.
		invalidateGithubCacheForBashCommand(command);

		const commandCwd = cwd ? resolveToCwd(cwd, this.session.cwd) : this.session.cwd;
		let cwdStat: fs.Stats;
		try {
			cwdStat = await fs.promises.stat(commandCwd);
		} catch (err) {
			if (isEnoent(err)) {
				throw new ToolError(`Working directory does not exist: ${commandCwd}`);
			}
			throw err;
		}
		if (!cwdStat.isDirectory()) {
			throw new ToolError(`Working directory is not a directory: ${commandCwd}`);
		}

		// A timeout of 0 is an explicit long-running-command contract: the user
		// must still cancel the call or job, but OMP does not impose a deadline.
		const requestedTimeoutSec = rawTimeout;
		const timeoutDisabled = requestedTimeoutSec === 0;
		const maxTimeout = this.session.settings.get("tools.maxTimeout");
		const timeoutSec = timeoutDisabled ? undefined : clampTimeout("bash", requestedTimeoutSec, maxTimeout);
		const timeoutMs = timeoutSec === undefined ? undefined : timeoutSec * 1000;
		const pendingNotices: string[] = [];
		if (timeoutSec !== undefined) {
			const timeoutClampNotice = formatTimeoutClampNotice(requestedTimeoutSec, timeoutSec, maxTimeout);
			if (timeoutClampNotice) pendingNotices.push(timeoutClampNotice);

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the path exists (ls the parent directory) and fix typos before re-running.
  2. Create the directory first if it is supposed to exist, or drop the cwd parameter to use the session cwd.
  3. If the session cwd vanished, restart/re-root the session in an existing directory.

Example fix

// before: cwd was never created
await bash.execute(id, { command: "ls", cwd: "/tmp/build-42/output" });

// after: ensure it exists first
await fs.mkdir("/tmp/build-42/output", { recursive: true });
await bash.execute(id, { command: "ls", cwd: "/tmp/build-42/output" });
Defensive patterns

Strategy: validation

Validate before calling

import { stat } from "node:fs/promises";
const dir = resolveToCwd(cwd, session.cwd);
try {
  if (!(await stat(dir)).isDirectory()) throw new Error(`not a directory: ${dir}`);
} catch (e) {
  if (e.code === "ENOENT") throw new Error(`path does not exist: ${dir}`);
  throw e;
}
await bash.execute(id, { command, cwd: dir });

Type guard

function isEnoentErr(e: unknown): e is NodeJS.ErrnoException & { code: "ENOENT" } {
  return typeof e === "object" && e !== null && "code" in e && (e as NodeJS.ErrnoException).code === "ENOENT";
}

Try / catch

try {
  await bash.execute(id, { command, cwd });
} catch (e) {
  if (e instanceof ToolError && e.message.startsWith("Working directory does not exist")) {
    await fs.mkdir(cwd, { recursive: true });
    return bash.execute(id, { command, cwd });
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing cwd=/path/that/does/not/exist to the bash tool; a leading `cd <missing-dir> && ...` in the command; the session cwd having been deleted while the session was open (e.g. tmpdir cleanup, branch switch removing a directory).

Common situations: Typo'd or partially-typed absolute paths; directories removed by an earlier command in the same session; agents constructing paths from stale listings; temp directories cleaned between commands.

Related errors


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