{"record":{"id":"1802c5d5fb40ca04","repo":"can1357/oh-my-pi","slug":"daemon-broker-token-is-empty","errorCode":null,"errorMessage":"Daemon broker token is empty","messagePattern":"Daemon broker token is empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/coding-agent/src/launch/broker.ts","lineNumber":1416,"sourceCode":"\tconst lease = await acquireBrokerLease(runtimeDir);\n\tif (!lease) return;\n\tsetProcessName(\"omp daemon broker\");\n\t// Record the scope's project dir so `omp ps` can map this hash-keyed runtime\n\t// dir back to its project (and derive the Windows pipe name) offline.\n\tvoid writeDaemonScopeMeta(runtimeDir, projectDir).catch(error => {\n\t\tlogger.warn(\"Failed to record daemon scope metadata\", {\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t});\n\t});\n\t// Reclaim sibling daemon scopes left behind by dead brokers (issue #8674).\n\t// Detached and non-throwing so it never delays clients connecting to us.\n\tvoid pruneDeadDaemonRuntimeDirs(runtimeDir).catch(error => {\n\t\tlogger.warn(\"Daemon runtime prune failed\", {\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t});\n\t});\n\tconst token = (await Bun.file(path.join(runtimeDir, TOKEN_FILE)).text()).trim();\n\tif (!token) throw new Error(\"Daemon broker token is empty\");\n\tconst broker = new DaemonBroker(projectDir, runtimeDir, token, idleGraceMs, restartBackoffBaseMs);\n\tconst cancelCleanup = postmortem.register(\"daemon-broker\", () => broker.shutdown());\n\ttry {\n\t\tawait broker.run();\n\t} finally {\n\t\tcancelCleanup();\n\t\tawait releaseBrokerLease(lease);\n\t}\n}\n","sourceCodeStart":1398,"sourceCodeEnd":1426,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/launch/broker.ts#L1398-L1426","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst token = (await Bun.file(path.join(runtimeDir, TOKEN_FILE)).text()).trim();\nif (!token) throw new Error(\"Daemon broker token is empty\");\n// after — regenerate instead of failing hard\nlet token = (await Bun.file(path.join(runtimeDir, TOKEN_FILE)).text()).trim();\nif (!token) { token = await createToken(runtimeDir); }","handlingStrategy":"retry","validationCode":"const tokenPath = path.join(runtimeDir, 'token');\nconst stat = await Bun.file(tokenPath).exists().then(ok => ok ? Bun.file(tokenPath) : null);\nif (stat && (await stat.text()).trim().length === 0) await fs.rm(tokenPath); // force regeneration","typeGuard":null,"tryCatchPattern":"try {\n  await startDaemonBrokerFromEnvironment();\n} catch (err) {\n  if (err.message.includes('token is empty')) {\n    await fs.rm(path.join(runtimeDir, 'token'), { force: true });\n    await startDaemonBrokerFromEnvironment(); // regenerate token\n  } else throw err;\n}","preventionTips":["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"],"tags":["ipc","auth","daemon","corrupt-state"],"backgroundTag":"empty-auth-token","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}