{"record":{"id":"98ddc9679fc72f0c","repo":"thedotmack/claude-mem","slug":"sync-hub-push-acked-index-must-be-an-object","errorCode":null,"errorMessage":"sync hub push: acked[${index}] must be an object","messagePattern":"sync hub push: acked\\[(.+?)\\] must be an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/sync/CloudSync.ts","lineNumber":990,"sourceCode":"    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);\n    const validatedAcked = acked.map((value, index): AckedOp => {\n      if (!value || typeof value !== 'object' || Array.isArray(value)) {\n        throw new Error(`sync hub push: acked[${index}] must be an object`);\n      }\n      const item = value as Record<string, unknown>;\n      if (\n        typeof item.id !== 'string'\n        || typeof item.kind !== 'string'\n        || (item.origin_local_id !== null && typeof item.origin_local_id !== 'string')\n        || typeof item.entity_rev !== 'string'\n        || typeof item.operation_sha256 !== 'string'\n        || typeof item.seq !== 'string'\n      ) {\n        throw new Error(`sync hub push: malformed acked[${index}]`);\n      }\n      assertCanonicalDecimal(item.entity_rev, { positive: true });\n      assertCanonicalDecimal(item.seq, { positive: true });\n      if (typeof item.origin_local_id === 'string') assertCanonicalDecimal(item.origin_local_id);\n      return item as unknown as AckedOp;\n    });\n    return {","sourceCodeStart":972,"sourceCodeEnd":1008,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/e2d1df569a8f04075d40e92461128ece7cf04c82/src/services/sync/CloudSync.ts#L972-L1008","documentation":"Inside the push response's acked array, element at the failing index is not an object — it is null, an array, or a JSON primitive. Each ack must be an object with id/kind/origin_local_id/entity_rev/operation_sha256/seq; validation stops before stamping, so no local rows change and flush() retries with backoff.","triggerScenarios":"Hub emits [null, ...] for skipped ops; a hub bug mapping the wrong list into acked (e.g. seq strings instead of objects); a proxy truncating/reordering JSON; stub fixtures with scalar entries.","commonSituations":"Hub refactor changed the ack item shape; partial hub deployment serving mixed versions; hand-written mock hub in integration tests.","solutions":["Log/inspect the raw acked array from a curl push to see what element type the hub actually returns","Fix the hub to emit one object per acknowledged op with all six required fields","If nulls represent 'not acked', remove them server-side — the acked array must contain only acknowledgments","Re-deploy hub and client together once the shape matches"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// Validate every ack entry's basic shape (hub tests / custom clients):\nfunction ackEntriesAreObjects(acked: unknown[]): boolean {\n  return acked.every(a => !!a && typeof a === 'object' && !Array.isArray(a));\n}","typeGuard":"function isAckedOpShape(v: unknown): v is Record<string, unknown> {\n  return !!v && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":"if (/acked\\[\\d+\\] must be an object/.test(sync.status().lastError ?? '')) {\n  // dump the raw acked array from the hub; nulls/scalars indicate a hub mapping bug\n}","preventionTips":["Hub: emit ack objects only for acknowledged ops — never null placeholders","Keep hub ack construction typed (a struct/interface, not ad-hoc JSON)","Include mixed ack arrays in hub fixtures and contract tests"],"tags":["sync","hub","protocol-validation","response-shape","ack"],"backgroundTag":"schema-validation-failed","analyzedSha":"e2d1df569a8f04075d40e92461128ece7cf04c82","analyzedAt":"2026-08-20T23:58:13.836Z","contentChangedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}