slopus/happy · warning · Error

Metadata version mismatch

Error message

Metadata version mismatch

What it means

Thrown inside ApiSessionClient's metadata update path when the server answers 'version-mismatch' for session metadata. If the server's version is newer, the client decrypts and adopts it locally first; the throw then signals the conflict to the update machinery so the write is retried against the adopted version.

Source

Thrown at packages/happy-cli/src/api/apiSession.ts:948

    skipExistingMessages() {
        this.skipInitialMessages = true;
    }

    updateMetadata(handler: (metadata: Metadata) => Metadata) {
        this.metadataLock.inLock(async () => {
            await backoff(async () => {
                let updated = handler(this.metadata!); // Weird state if metadata is null - should never happen but here we are
                const answer = await this.socket.emitWithAck('update-metadata', { sid: this.sessionId, expectedVersion: this.metadataVersion, metadata: encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, updated)) });
                if (answer.result === 'success') {
                    this.metadata = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(answer.metadata));
                    this.metadataVersion = answer.version;
                } else if (answer.result === 'version-mismatch') {
                    if (answer.version > this.metadataVersion) {
                        this.metadataVersion = answer.version;
                        this.metadata = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(answer.metadata));
                    }
                    throw new Error('Metadata version mismatch');
                } else if (answer.result === 'error') {
                    // Hard error - ignore
                }
            });
        });
    }

    /**
     * Update session agent state
     * @param handler - Handler function that returns the updated agent state
     */
    updateAgentState(handler: (metadata: AgentState) => AgentState) {
        logger.debugLargeJson('Updating agent state', this.agentState);
        this.agentStateLock.inLock(async () => {
            await backoff(async () => {
                let updated = handler(this.agentState || {});
                const answer = await this.socket.emitWithAck('update-state', { sid: this.sessionId, expectedVersion: this.agentStateVersion, agentState: updated ? encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, updated)) : null });
                if (answer.result === 'success') {

View on GitHub (pinned to b824cd0a46)

Solutions

  1. Rely on the built-in retry — the client already adopted the newer server metadata
  2. Avoid simultaneous metadata edits to one session from multiple clients
  3. If it repeats, reload the session state from the server before writing metadata
Defensive patterns

Strategy: retry

Try / catch

try {
  await updateSessionMetadata(sessionId, metadata);
} catch (e) {
  if (e.message === 'Metadata version mismatch') {
    // newer server metadata already adopted; retry once
    await updateSessionMetadata(sessionId, metadata);
  } else throw e;
}

Prevention

When it happens

Trigger: The same session's metadata is written from two places (two devices/CLI instances, or app plus CLI) so the local metadataVersion lags the server's.

Common situations: Using happy CLI and mobile/web app on the same session simultaneously; a stale background sync loop retrying an old version; session resumed on another machine between updates.

Related errors


AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31). Data as JSON: /api/errors/a4e1f44d9d3e26c9. Report an issue: GitHub.