can1357/oh-my-pi · error
Daemon cwd is not a directory: ${spec.cwd}
Error message
Daemon cwd is not a directory: ${spec.cwd} What it means
DaemonBroker.start stats spec.cwd before spawning and requires it to exist as a directory. If the path does not exist fs.stat throws ENOENT, and if it exists but is not a directory (a file, symlink to a file, etc.) this error is thrown. The broker refuses to launch a daemon with an invalid working directory.
Source
Thrown at packages/coding-agent/src/launch/broker.ts:632
let record: ManagedDaemon;
try {
const existing = this.#records.get(spec.name);
if (existing) await this.#refreshDetached(existing);
if (existing && !terminalState(existing.snapshot.state)) {
throw new Error(`Daemon ${spec.name} is already ${existing.snapshot.state}`);
}
if (existing && existing.pendingCompletions.length > 0) {
throw new Error(`Daemon ${spec.name} has unacknowledged completion notifications`);
}
if (spec.ready?.log) {
try {
new RegExp(spec.ready.log, "u");
} catch (error) {
throw new Error(`Invalid readiness regex: ${error instanceof Error ? error.message : String(error)}`);
}
}
const stat = await fs.stat(spec.cwd);
if (!stat.isDirectory()) throw new Error(`Daemon cwd is not a directory: ${spec.cwd}`);
const dir = path.join(this.#runtimeDir, "daemons", spec.name);
const now = Date.now();
record = {
spec,
snapshot: {
name: spec.name,
id: crypto.randomUUID(),
state: "starting",
createdAt: now,
startedAt: now,
restartCount: 0,
outputBytes: 0,
owner,
persist: spec.persist,
detached: spec.detached,
},
dir,
log: await DaemonLog.open(dir),View on GitHub (pinned to 9690622007)
Solutions
- Create the directory first: `mkdir -p <cwd>` (or fs.mkdir(recursive: true)) before starting the daemon.
- Fix the cwd in the spec to an absolute path to an existing directory.
- Check for typos or stale config pointing at a removed/renamed directory.
Example fix
// before
await broker.start({ name: "worker", cwd: "/srv/app/workers", ... });
// after
import * as fs from "node:fs";
fs.mkdirSync("/srv/app/workers", { recursive: true });
await broker.start({ name: "worker", cwd: "/srv/app/workers", ... }); Defensive patterns
Strategy: validation
Validate before calling
import { statSync } from "node:fs";
const st = statSync(spec.cwd); // throws ENOENT if missing
if (!st.isDirectory()) throw new Error(`cwd is not a directory: ${spec.cwd}`); Try / catch
try {
await broker.start(spec);
} catch (err) {
if (err instanceof Error && (err.message.startsWith("Daemon cwd is not a directory") || (err as NodeJS.ErrnoException).code === "ENOENT")) {
fs.mkdirSync(spec.cwd, { recursive: true });
await broker.start(spec);
} else throw err;
} Prevention
- Resolve cwd to an absolute path at config load time and verify it exists.
- Create working directories as part of setup/bootstrap before launching daemons.
- Never point cwd at a file path or a directory that build steps may delete.
When it happens
Trigger: Passing a DaemonSpec whose cwd points to a regular file, or whose cwd path does not exist at all (fs.stat rejects with ENOENT which propagates to the caller).
Common situations: Typo'd or relative path in config; the directory was deleted or renamed after config was written; running from a checkout where a build artifact directory hasn't been created yet.
Related errors
- cannot access {}: Not a directory
- failed to access {0}: Not a directory
- Unable to read OMP_AUTH_BROKER_ACCOUNT_POOL_FILE at ${filePa
- Not a file: ${shortenPath(resolved)}
- File not found: ${path}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/ef1fa6c57eeaf5e4.
Report an issue: GitHub.