can1357/oh-my-pi · error
Daemon broker authentication failed
Error message
Daemon broker authentication failed
What it means
DaemonBroker's socket line handler parses each inbound line as a daemon wire request and compares request.token against the broker's shared secret (#token). Any mismatch throws 'Daemon broker authentication failed' before the request is dispatched or the socket is marked authenticated, protecting the local daemon-control RPC from unauthorized processes on the machine.
Source
Thrown at packages/coding-agent/src/launch/broker.ts:477
});
socket.on("close", () => {
this.#sockets.delete(socket);
if (!authenticated) return;
this.#clients.delete(socket);
this.#scheduleIdleShutdown();
for (const [owner, registration] of this.#ownerSockets) {
if (registration.socket === socket) this.#ownerSockets.delete(owner);
}
});
}
async #handleLine(socket: net.Socket, line: string, onAuthenticated: () => void): Promise<void> {
let id = "unknown";
try {
const decoded: unknown = JSON.parse(line);
const request = parseDaemonWireRequest(decoded);
id = request.id;
if (request.token !== this.#token) throw new Error("Daemon broker authentication failed");
onAuthenticated();
for (const owner of request.completionUnsubscribes ?? []) {
const subscriptionId = this.#completionSubscriptions.get(owner);
if (
!this.#completionSubscriptions.has(owner) ||
(subscriptionId !== undefined && subscriptionId !== request.completionSubscriptionId)
) {
continue;
}
this.#ownerSockets.delete(owner);
this.#completionSubscriptions.delete(owner);
await this.#setRecordCompletionCapability(owner, false);
this.#pendingCompletions.delete(owner);
}
for (const completionId of request.completionAcks ?? []) {
for (const [owner, pending] of this.#pendingCompletions) {
const registration = this.#ownerSockets.get(owner);
if (View on GitHub (pinned to 9690622007)
Solutions
- Ensure the client loads the same token the broker was started with (same token file / env source) and restart the client
- Restart the broker so it and its clients are recreated from one token source together
- Check for stale broker instances (kill old daemons/brokers) so you are not authenticating against a defunct token
- If you own the wire client, log the token source (not the token) on both sides to confirm they resolve to the same file
Example fix
// before
const token = readToken('~/.omp/daemon.token'); // stale file from previous install
send(socket, { id, op: 'start', token }); // Daemon broker authentication failed
// after
const token = await brokerClient.currentToken(); // read live token from broker's authoritative location
send(socket, { id, op: 'start', token }); Defensive patterns
Strategy: try-catch
Validate before calling
const expectedToken = await readBrokerToken(); // same authoritative source the broker uses
if (!request.token || request.token !== expectedToken) {
throw new Error('Refusing to send: client token does not match broker token');
} Try / catch
try {
await daemonRpc(request);
} catch (err) {
if (err instanceof Error && err.message === 'Daemon broker authentication failed') {
await refreshBrokerToken(); // re-read token file / restart broker
return daemonRpc({ ...request, token: currentToken() });
}
throw err;
} Prevention
- Read the token from the broker's canonical location at connect time, never cache it across broker restarts
- Version-bump the token file path when the install layout changes so stale tokens are not silently reused
- Kill superseded broker instances before starting a new one to avoid authenticating against the wrong process
- Never log or embed tokens in configs, scripts, or error reports
When it happens
Trigger: A client connects to the broker's socket and sends a wire request whose token field differs from the broker's configured token — wrong or stale token file, token regenerated after broker restart, or an unauthenticated/malicious local process probing the socket.
Common situations: Client and broker reading the token from different locations after a config change or reinstall; multiple broker versions running concurrently with independently generated tokens; a client cached an old token from a previous daemon lifetime; local security tooling or another user's process port-scanning the socket.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- blob daemon ${input} responded ${response.status}
- Daemon ${operation.name} is ${record.snapshot.state}
- Daemon broker environment is incomplete
- Daemon broker token is empty
- 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/15b3f024ec40a252.
Report an issue: GitHub.