slopus/happy · warning · Error
Daemon state version mismatch
Error message
Daemon state version mismatch
What it means
Thrown by updateDaemonState when the server reports 'version-mismatch' for daemon runtime state. As with metadata, the client first adopts the server's newer daemonStateVersion/daemonState, then throws to trigger a retry with the refreshed version. It is an expected conflict signal, not a fatal fault.
Source
Thrown at packages/happy-cli/src/api/apiMachine.ts:422
await backoff(async () => {
const updated = handler(this.machine.daemonState);
const answer = await this.socket.emitWithAck('machine-update-state', {
machineId: this.machine.id,
daemonState: encodeBase64(encrypt(this.machine.encryptionKey, this.machine.encryptionVariant, updated)),
expectedVersion: this.machine.daemonStateVersion
});
if (answer.result === 'success') {
this.machine.daemonState = decrypt(this.machine.encryptionKey, this.machine.encryptionVariant, decodeBase64(answer.daemonState));
this.machine.daemonStateVersion = answer.version;
logger.debug('[API MACHINE] Daemon state updated successfully');
} else if (answer.result === 'version-mismatch') {
if (answer.version > this.machine.daemonStateVersion) {
this.machine.daemonStateVersion = answer.version;
this.machine.daemonState = decrypt(this.machine.encryptionKey, this.machine.encryptionVariant, decodeBase64(answer.daemonState));
}
throw new Error('Daemon state version mismatch'); // Triggers retry
}
});
}
connect() {
const serverUrl = configuration.serverUrl.replace(/^http/, 'ws');
logger.debug(`[API MACHINE] Connecting to ${serverUrl}`);
this.socket = io(serverUrl, {
transports: ['websocket'],
auth: {
token: this.token,
clientType: 'machine-scoped' as const,
machineId: this.machine.id,
happyClient: `cli-daemon/${configuration.currentCliVersion}`
},
path: '/v1/updates',
reconnection: false,View on GitHub (pinned to b824cd0a46)
Solutions
- Allow the surrounding retry in connect() to re-send with the adopted version
- Stop extra daemon instances so only one writer exists
- If recurring, re-sync daemon state from the server before pushing updates
Defensive patterns
Strategy: retry
Try / catch
try {
await updateDaemonState(state);
} catch (e) {
if (e.message === 'Daemon state version mismatch') {
// server version already adopted locally; retry converges
await updateDaemonState(state);
} else throw e;
} Prevention
- Prevent duplicate daemon processes (pidfile/lock)
- Let connect()'s retry loop handle the conflict
- Re-sync daemon state after long disconnects before pushing
When it happens
Trigger: Concurrent daemon-state updates from two daemon processes or a stale update issued by connect()'s update loop after another writer advanced the version.
Common situations: Duplicate daemon instances; daemon reconnecting after another instance already bumped daemonStateVersion; leftover state updates in flight across restarts.
Related errors
AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31).
Data as JSON: /api/errors/518d698a3138eb85.
Report an issue: GitHub.