{"record":{"id":"59415446773364d9","repo":"thedotmack/claude-mem","slug":"origin-device-id-does-not-match-authenticated-x-de","errorCode":null,"errorMessage":"origin_device_id does not match authenticated X-Device-Id","messagePattern":"origin_device_id does not match authenticated X-Device-Id","errorType":"validation","errorClass":"Error","httpStatus":409,"severity":"error","filePath":"workers/sync-hub/src/do/SyncHub.ts","lineNumber":382,"sourceCode":"\t\t} catch (error) {\n\t\t\tconsole.error(\"sync-hub fan-out failed (advisory; push unaffected):\", error);\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------\n\t// Canonical append path and client cursor reads.\n\t// ---------------------------------------------------------------------\n\n\tasync pushOps(deviceId: string, ops: PushOp[], deviceName: string | null = null): Promise<PushOutcome> {\n\t\tlet rows: ValidatedOp[];\n\t\ttry {\n\t\t\tif (typeof deviceId !== \"string\" || deviceId.length === 0) throw invalid(\"deviceId must be non-empty\");\n\t\t\tif (!Array.isArray(ops)) throw invalid(\"ops must be an array\");\n\t\t\trows = await Promise.all(ops.map(async (op, index) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst parsed = await parseCanonicalOperation(op);\n\t\t\t\t\tif (parsed.body.origin_device_id !== deviceId) {\n\t\t\t\t\t\tthrow new Error(\"origin_device_id does not match authenticated X-Device-Id\");\n\t\t\t\t\t}\n\t\t\t\t\treturn parsed;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow invalid(`ops[${index}] ${error instanceof Error ? error.message : String(error)}`);\n\t\t\t\t}\n\t\t\t}));\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.startsWith(INVALID_OPS_PREFIX)) {\n\t\t\t\treturn { refused: true, error: error.message };\n\t\t\t}\n\t\t\tif (isDeviceLimitError(error)) return { refused: true, error: DEVICE_LIMIT_ERROR };\n\t\t\tthrow error;\n\t\t}\n\n\t\tconst sql = this.ctx.storage.sql;\n\t\tconst now = Date.now();\n\t\tconst nowDecimal = String(now);\n\t\tconst headBefore = this.headSeq();","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/workers/sync-hub/src/do/SyncHub.ts#L364-L400","documentation":"Error \"origin_device_id does not match authenticated X-Device-Id\" thrown in thedotmack/claude-mem.","triggerScenarios":"Fires in the SyncHub durable object when an operation's origin_device_id does not match the authenticated X-Device-Id header, indicating a spoofed or replayed request, a buggy client sending another device's operations, or a misconfigured proxy stripping headers. Guard at workers/sync-hub/src/do/SyncHub.ts:382 enforces that a device can only write its own operations.","commonSituations":"See trigger scenarios.","solutions":["Ensure the client sets origin_device_id in each op body equal to the X-Device-Id header it authenticated with.","If the device id changed (reinstall/rotation), re-register the device and resync rather than replaying ops under the old id."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}