thedotmack/claude-mem · error
sync hub status: response must be an object
Error message
sync hub status: response must be an object
What it means
Thrown when the parsed JSON status body is not a non-null, non-array object (parsed is falsy, typeof !== 'object', or Array.isArray). The hub must return a JSON object; arrays, primitives, or null are rejected before any field is read.
Source
Thrown at src/services/sync/CloudSync.ts:606
},
signal: AbortSignal.timeout(this.requestTimeoutMs),
});
checkedAt = Date.now();
const syncMode = response.headers.get('X-Sync-Mode');
if (syncMode !== null || response.ok) this.emitSyncMode(syncMode);
if (!response.ok) {
const body = (await response.text().catch(() => '')).slice(0, 200);
throw new Error(`sync hub status ${response.status}: ${body}`);
}
let parsed: unknown;
try {
parsed = await response.json();
} catch {
throw new Error('sync hub status: response is not JSON');
}
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new Error('sync hub status: response must be an object');
}
const record = parsed as Record<string, unknown>;
if (record.protocol_version !== 2) {
throw new Error('sync hub status: response requires protocol_version 2');
}
if (
typeof record.epoch !== 'string'
|| typeof record.head_seq !== 'string'
|| typeof record.projected_seq !== 'string'
) {
throw new Error('sync hub status: response requires decimal-string epoch/head_seq/projected_seq');
}
const epoch = assertCanonicalDecimal(record.epoch, { positive: true });
const headSeq = assertCanonicalDecimal(record.head_seq);
const projectedSeq = assertCanonicalDecimal(record.projected_seq);
if (compareCanonicalDecimals(projectedSeq, headSeq) > 0) {
throw new Error('sync hub status: projected_seq exceeds head_seq');
}View on GitHub (pinned to d768ba3643)
Solutions
- Log the parsed value's type to confirm what the hub actually returned.
- Confirm hubUrl and the request path are exactly /v1/sync/status on the correct hub.
- Verify hub protocol_version compatibility — the client expects a status object, not a list.
- If the hub changed its response shape, align client and hub versions.
Example fix
// before: hub returns an array for the status route
// GET /v1/sync/status -> [{"epoch":...}]
// after: hub returns the expected object
// GET /v1/sync/status -> {"protocol_version":2,"epoch":"...",...} Defensive patterns
Strategy: validation
Type guard
function isHubStatusNotObject(e: unknown): boolean {
return e instanceof Error && /sync hub status: response must be an object/i.test(e.message);
} Try / catch
try { await cloudSync.status(); }
catch (e) { if (isHubStatusNotObject(e)) { markHubMisconfigured(e.message); return; } throw e; } Prevention
- Pin the hub version to one whose /v1/sync/status returns a JSON object.
- Add a contract test asserting the status route returns an object, not an array or primitive.
- Ensure the request hits the status route and not a generic collection endpoint.
When it happens
Trigger: The hub returned valid JSON but it was an array (e.g. a list endpoint by mistake), a JSON primitive (string/number/boolean), or null. Typically a routing mistake where a different endpoint answered /v1/sync/status.
Common situations: hubUrl routes to a generic collection endpoint that returns an array; a load balancer returning a JSON-formatted health string; the hub deployed a version where /v1/sync/status returns a different shape.
Related errors
- sync hub status: response is not JSON
- sync hub push: response is not JSON
- sync hub push: response missing acked array
- sync hub status: response requires decimal-string epoch/head
- sync hub status ${response.status}: ${body}
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/e2ebce574b9441e5.
Report an issue: GitHub.