can1357/oh-my-pi · critical
Daemon broker token is empty
Error message
Daemon broker token is empty
What it means
After startup the broker reads the auth token file from the runtime directory and trims it. The token file exists but is empty, so the broker refuses to start — it requires a non-empty shared secret to authenticate broker connections.
Source
Thrown at packages/coding-agent/src/launch/broker.ts:1416
const lease = await acquireBrokerLease(runtimeDir);
if (!lease) return;
setProcessName("omp daemon broker");
// Record the scope's project dir so `omp ps` can map this hash-keyed runtime
// dir back to its project (and derive the Windows pipe name) offline.
void writeDaemonScopeMeta(runtimeDir, projectDir).catch(error => {
logger.warn("Failed to record daemon scope metadata", {
error: error instanceof Error ? error.message : String(error),
});
});
// Reclaim sibling daemon scopes left behind by dead brokers (issue #8674).
// Detached and non-throwing so it never delays clients connecting to us.
void pruneDeadDaemonRuntimeDirs(runtimeDir).catch(error => {
logger.warn("Daemon runtime prune failed", {
error: error instanceof Error ? error.message : String(error),
});
});
const token = (await Bun.file(path.join(runtimeDir, TOKEN_FILE)).text()).trim();
if (!token) throw new Error("Daemon broker token is empty");
const broker = new DaemonBroker(projectDir, runtimeDir, token, idleGraceMs, restartBackoffBaseMs);
const cancelCleanup = postmortem.register("daemon-broker", () => broker.shutdown());
try {
await broker.run();
} finally {
cancelCleanup();
await releaseBrokerLease(lease);
}
}
View on GitHub (pinned to 9690622007)
Solutions
- Delete the runtime directory (or just the token file) so the client's readOrCreateToken regenerates a fresh token, then restart
- Verify no concurrent broker is writing the same runtime dir; ensure one broker per project dir
- Check disk full / permission issues that could truncate the token file
Example fix
// before
const token = (await Bun.file(path.join(runtimeDir, TOKEN_FILE)).text()).trim();
if (!token) throw new Error("Daemon broker token is empty");
// after — regenerate instead of failing hard
let token = (await Bun.file(path.join(runtimeDir, TOKEN_FILE)).text()).trim();
if (!token) { token = await createToken(runtimeDir); } Defensive patterns
Strategy: retry
Validate before calling
const tokenPath = path.join(runtimeDir, 'token'); const stat = await Bun.file(tokenPath).exists().then(ok => ok ? Bun.file(tokenPath) : null); if (stat && (await stat.text()).trim().length === 0) await fs.rm(tokenPath); // force regeneration
Try / catch
try {
await startDaemonBrokerFromEnvironment();
} catch (err) {
if (err.message.includes('token is empty')) {
await fs.rm(path.join(runtimeDir, 'token'), { force: true });
await startDaemonBrokerFromEnvironment(); // regenerate token
} else throw err;
} Prevention
- Never share one runtime dir between concurrent brokers
- Regenerate (delete + recreate) the token file instead of hand-editing it
- Check for disk-full or crash-truncation when tokens appear empty
When it happens
Trigger: The token file at <runtimeDir>/<TOKEN_FILE> was truncated by a crash, created empty by a partial initialization, or wiped by cleanup/disk pressure while the worker was starting.
Common situations: Concurrent brokers racing on the same runtime dir; kill -9 during token generation; stale runtime dirs reused after a reboot; pruneDeadDaemonRuntimeDirs removing files from a live dir.
Related errors
- blob daemon ${input} responded ${response.status}
- Daemon broker authentication failed
- Daemon ${operation.name} is ${record.snapshot.state}
- Daemon broker environment is incomplete
- Timed out initializing daemon broker token in ${runtimeDir}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/1802c5d5fb40ca04.
Report an issue: GitHub.