{"record":{"id":"be29f97a63d19ced","repo":"thedotmack/claude-mem","slug":"sync-hub-push-res-status-body","errorCode":null,"errorMessage":"sync hub push ${res.status}: ${body}","messagePattern":"sync hub push (.+?): (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/services/sync/CloudSync.ts","lineNumber":1196,"sourceCode":"      },\n      body: requestBody,\n      signal: AbortSignal.timeout(this.requestTimeoutMs),\n    });\n    // Mode hint BEFORE the ok-check: the kill-switch header rides error\n    // responses too, and a client that only learned the mode from happy\n    // paths would keep hammering the socket through an incident.\n    // Asymmetric on purpose (SyncClient.onSyncModeHint contract): header\n    // PRESENCE is emitted regardless of status; header ABSENCE is only\n    // emitted (as null = \"cleared\") from an OK response — absence on an\n    // error response is ambiguous (a degraded auth upstream 503s without\n    // the funnel) and must not read as \"switch cleared\".\n    const syncMode = res.headers.get('X-Sync-Mode');\n    if (syncMode !== null || res.ok) {\n      this.emitSyncMode(syncMode);\n    }\n    if (!res.ok) {\n      const body = (await res.text().catch(() => '')).slice(0, 200);\n      throw new Error(`sync hub push ${res.status}: ${body}`);\n    }\n    let parsed: unknown;\n    try {\n      parsed = await res.json();\n    } catch {\n      throw new Error('sync hub push: response is not JSON');\n    }\n    const acked = (parsed as { acked?: unknown } | null)?.acked;\n    if (!Array.isArray(acked)) {\n      throw new Error('sync hub push: response missing acked array');\n    }\n    const headSeq = (parsed as { head_seq?: unknown }).head_seq;\n    const projectedSeq = (parsed as { projected_seq?: unknown }).projected_seq;\n    if (typeof headSeq !== 'string' || typeof projectedSeq !== 'string') {\n      throw new Error('sync hub push: response requires decimal-string head_seq/projected_seq');\n    }\n    assertCanonicalDecimal(headSeq);\n    assertCanonicalDecimal(projectedSeq);","sourceCodeStart":1178,"sourceCodeEnd":1214,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/sync/CloudSync.ts#L1178-L1214","documentation":"pushOps throws this when the sync hub responds with a non-OK HTTP status. The first 200 characters of the response body are included to surface the hub's error detail. It wraps any server-side rejection (auth, protocol, validation, server errors) of a push request.","triggerScenarios":"POST to {hubUrl}/v1/sync/ops returns 401 (expired/invalid bearer token), 400 (bad ops or protocol_version mismatch), 413 (body too large), or 5xx while the client expects a PushResponse.","commonSituations":"Expired sync token after re-auth elsewhere; hub deployed a newer protocol version; hub is temporarily down or behind a misconfigured proxy returning HTML error pages.","solutions":["Read the embedded status and body snippet to identify the hub's rejection reason.","If 401, refresh the sync token in ~/.claude-mem settings/.env and reconfigure CloudSync.","If 400/protocol errors, update the client or hub so protocol versions match.","Retry with backoff for 5xx; check hub availability/proxy config."],"exampleFix":"// before\nawait sync.pushNow(); // throws opaque\n// after\ntry {\n  await sync.pushNow();\n} catch (e) {\n  if (/sync hub push 401/.test(e.message)) await refreshTokenAndRetry();\n  else throw e;\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await client.pushOps(ops); } catch (e) {\n  const m = /sync hub push (\\d{3})/.exec(e.message);\n  if (m && +m[1] >= 500) await retryWithBackoff(() => client.pushOps(ops));\n  else if (m && +m[1] === 401) await refreshToken();\n  else throw e;\n}","preventionTips":["Rotate sync tokens before expiry.","Keep client and hub protocol versions in lockstep.","Alert on persistent non-2xx push responses."],"tags":["sync","http","network"],"backgroundTag":"http-error-response","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}