can1357/oh-my-pi · error

Unknown daemon ${name}${names.length ? `. Available: ${names

Error message

Unknown daemon ${name}${names.length ? `. Available: ${names.join(", ")}` : ""}

What it means

DaemonBroker.#record is the internal lookup for a managed daemon by name. When no record with that name exists, it throws this error listing all currently known daemon names (or nothing if the registry is empty). Every operation targeting an unregistered daemon funnels through here, making this the canonical 'unknown daemon name' error.

Source

Thrown at packages/coding-agent/src/launch/broker.ts:1189

	}

	async #waitUntil(record: ManagedDaemon, condition: () => boolean, timeoutMs: number): Promise<boolean> {
		const deadline = Date.now() + Math.max(0, timeoutMs);
		while (Date.now() < deadline) {
			await this.#refreshDetached(record);
			if (condition()) return true;
			if (this.#shuttingDown && terminalState(record.snapshot.state)) return condition();
			await Bun.sleep(50);
		}
		await this.#refreshDetached(record);
		return condition();
	}

	#record(name: string): ManagedDaemon {
		const record = this.#records.get(name);
		if (record) return record;
		const names = [...this.#records.keys()];
		throw new Error(`Unknown daemon ${name}${names.length ? `. Available: ${names.join(", ")}` : ""}`);
	}

	#persist(record: ManagedDaemon): void {
		const metaPath = path.join(record.dir, META_FILE);
		const tempPath = `${metaPath}.${process.pid}.tmp`;
		const metadata = {
			daemon: { ...record.snapshot },
			spec: record.spec,
			completionEvents: record.completionCapable,
			completionSubscriptionId: record.completionSubscriptionId,
			completionPending: record.pendingCompletions.length > 0,
			pendingCompletion: record.pendingCompletions.at(-1)?.daemon,
			pendingCompletions: record.pendingCompletions.map(completion => ({
				...completion,
				daemon: { ...completion.daemon },
			})),
		};
		record.persistQueue = record.persistQueue

View on GitHub (pinned to 9690622007)

Solutions

  1. Use a name from the 'Available:' list in the message, or run a list operation to see registered daemons.
  2. Start the daemon with broker.start if it doesn't exist yet.
  3. Verify the client and broker use the same runtimeDir so the registry matches what you expect.

Example fix

// before
await broker.send({ name: "buildr", data: "go\n" }); // typo
// after
const daemons = await broker.list();
const name = daemons.find(d => d.name === "builder")?.name;
if (name) await broker.send({ name, data: "go\n" });
Defensive patterns

Strategy: validation

Validate before calling

const daemons = await broker.list();
if (!daemons.some(d => d.name === name)) {
  throw new Error(`daemon '${name}' not registered; available: ${daemons.map(d => d.name).join(", ")}`);
}

Type guard

function knowsDaemon(daemons: { name: string }[], name: string): boolean {
  return daemons.some(d => d.name === name);
}

Try / catch

try {
  await broker.send({ name, data });
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Unknown daemon ")) {
    const daemons = await broker.list();
    // pick correct name from daemons or start the daemon
  } else throw err;
}

Prevention

When it happens

Trigger: Any daemon operation (send, wait, stop, get) with a name that was never started in this broker session, was already fully removed, or is misspelled. The registry is in-memory (#records), so records created by a previous broker process also won't be found.

Common situations: Typos in the daemon name; client pointing at a different runtimeDir than the broker that owns the daemon; broker process restarted and its in-memory registry re-seeded differently; operating on a daemon started in another project/runtime directory.

Related errors


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