can1357/oh-my-pi · error
Daemon ${spec.name} has unacknowledged completion notificati
Error message
Daemon ${spec.name} has unacknowledged completion notifications What it means
DaemonBroker.start throws this when a daemon with the same name was previously launched and exited, but its completion notifications have not been acknowledged yet. The broker keeps pending completions per record so callers can observe daemon termination; starting a new daemon under the same name before acknowledging would silently discard that record. The caller must acknowledge completions (or remove the daemon record) before reusing the name.
Source
Thrown at packages/coding-agent/src/launch/broker.ts:622
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)}`);
}
}
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",View on GitHub (pinned to 9690622007)
Solutions
- Acknowledge the pending completion notifications for that daemon name (via the broker's completion/notification acknowledge API or list operation) before calling start again.
- Remove or stop the stale daemon record so pendingCompletions are cleared, then start the daemon.
- Use a different daemon name for the new launch if the old notifications must be preserved.
Example fix
// before
await broker.start({ name: "build", ... });
// after
await broker.acknowledgeCompletions("build"); // drain pending exit notifications
await broker.start({ name: "build", ... }); Defensive patterns
Strategy: validation
Validate before calling
const rec = await broker.get?.(spec.name);
if (rec && (rec.pendingCompletions?.length ?? 0) > 0) {
await broker.acknowledgeCompletions(spec.name); // or use another name
}
await broker.start(spec); Try / catch
try {
await broker.start(spec);
} catch (err) {
if (err instanceof Error && err.message.includes("unacknowledged completion notifications")) {
await broker.acknowledgeCompletions(spec.name);
await broker.start(spec);
} else throw err;
} Prevention
- Always poll/acknowledge completion notifications after a daemon exits, before reusing its name.
- Wrap start calls in a helper that drains pendingCompletions for the name first.
- Use unique daemon names per logical run to avoid record reuse entirely.
When it happens
Trigger: Calling broker.start(spec) for a daemon name whose existing record has pendingCompletions.length > 0 — i.e. the previous daemon under that name terminated and its exit notification was never fetched/acknowledged.
Common situations: A daemon crashed or exited and the client never polled for or acknowledged the completion event, then the operator re-runs the launch command with the same daemon name. Also happens after restarting a supervisor client that lost track of prior notifications.
Related errors
- Daemon ${spec.name} is already starting
- Daemon ${spec.name} is already ${existing.snapshot.state}
- Daemon ${operation.name} is ${record.snapshot.state}
- blob daemon ${input} responded ${response.status}
- blob broker exposure failed to start
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/6dcab51d20a125e5.
Report an issue: GitHub.