can1357/oh-my-pi · error
Daemon ${spec.name} is already starting
Error message
Daemon ${spec.name} is already starting What it means
DaemonBroker.#start tracks in-flight startups in a #startingNames set and throws 'Daemon <name> is already starting' if a start request for the same name arrives while a previous start is still in progress. This prevents duplicate spawns and racy record creation for the same daemon name.
Source
Thrown at packages/coding-agent/src/launch/broker.ts:611
}
}
async #start(spec: DaemonSpec, owner?: string): Promise<DaemonRpcResult> {
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,47}$/.test(spec.name)) {
throw new Error("Daemon name must be 1-48 letters, numbers, dots, underscores, or hyphens");
}
if (spec.detached && spec.pty) {
throw new Error("A detached daemon cannot allocate a PTY");
}
if (
spec.pty &&
process.platform === "win32" &&
[".bat", ".cmd"].includes(path.extname(spec.application).toLowerCase())
) {
throw new Error('Windows batch files require application "cmd.exe" with the batch path after "/c"');
}
if (this.#startingNames.has(spec.name)) {
throw new Error(`Daemon ${spec.name} is already starting`);
}
this.#startingNames.add(spec.name);
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)}`);
}View on GitHub (pinned to 9690622007)
Solutions
- Wait for the in-flight start to finish and reuse its result instead of issuing a second start for the same name
- Query the daemon's state first and skip start if it already exists/is starting
- Add client-side request coalescing/mutex keyed by daemon name
- Retry after receiving this error with backoff, expecting the first start to complete
Example fix
// before
Promise.all([broker.start(spec), broker.start(spec)]); // second throws 'already starting'
// after
const starts = new Map<string, Promise<DaemonRpcResult>>();
const once = (spec: DaemonSpec) => {
let p = starts.get(spec.name);
if (!p) { p = broker.start(spec).finally(() => starts.delete(spec.name)); starts.set(spec.name, p); }
return p;
};
await Promise.all([once(spec), once(spec)]); Defensive patterns
Strategy: retry
Validate before calling
const inflight = new Map<string, Promise<DaemonRpcResult>>();
function startOnce(spec: DaemonSpec): Promise<DaemonRpcResult> {
let p = inflight.get(spec.name);
if (!p) {
p = broker.start(spec).finally(() => inflight.delete(spec.name));
inflight.set(spec.name, p);
}
return p;
} Try / catch
try {
return await startOnce(spec);
} catch (err) {
if (err instanceof Error && /is already starting$/.test(err.message)) {
await Bun.sleep(500); // or poll daemon state until start settles
return startOnce(spec);
}
throw err;
} Prevention
- Coalesce concurrent start requests per daemon name on the client side
- Disable/re-debounce UI triggers (buttons, hotkeys) while a start is pending
- Use bounded backoff for retries instead of immediate re-issue
- Prefer a status query over a blind start when unsure of daemon state
When it happens
Trigger: Issuing two overlapping start RPCs with the same spec.name — e.g. double-clicking a start button, retry logic firing while the first start is still initializing, or several clients starting the same named daemon concurrently.
Common situations: UI without request de-duplication; network retries with no jitter on slow daemon spawn; orchestration scripts racing multiple workers to start the same daemon; slow #start (waiting on readiness logs) widening the race window.
Related errors
- OAuth refresh ownership was lost before persistence
- No credential with id=${id}
- session header changed during stats cleanup: ${session.path}
- Daemon ${spec.name} is already ${existing.snapshot.state}
- Daemon ${spec.name} has unacknowledged completion notificati
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/aac60c7b4913d879.
Report an issue: GitHub.