thedotmack/claude-mem · error

sync hub status: response requires decimal-string epoch/head

Error message

sync hub status: response requires decimal-string epoch/head_seq/projected_seq

What it means

Thrown when any of epoch, head_seq, or projected_seq on the status object is not a string (typeof check fails). All three must be decimal strings (canonical form, validated further by assertCanonicalDecimal with epoch requiring positive). The hub serializes large uint64 sequence numbers as strings to avoid JS number precision loss, so a number or missing field is rejected here.

Source

Thrown at src/services/sync/CloudSync.ts:617

      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');
      }
      this.hubStatus = {
        checkedAt,
        reachable: true,
        epoch,
        headSeq,
        projectedSeq,
        error: null,
      };
    } catch (error) {
      const raw = error instanceof Error ? error.message : String(error);
      const safe = this.token === '' ? raw : raw.split(this.token).join('[REDACTED]');

View on GitHub (pinned to d768ba3643)

Solutions

  1. Log the raw record to see which field is missing or mistyped.
  2. Ensure the hub emits epoch/head_seq/projected_seq as canonical decimal strings (no leading zeros, base-10, within uint64).
  3. Align hub and client versions so the field shapes match the v2 contract.
  4. epoch must additionally be positive (non-zero).

Example fix

// before: hub emits numbers
// {"protocol_version":2,"epoch":1,"head_seq":42,"projected_seq":42}
// after: hub emits decimal strings
// {"protocol_version":2,"epoch":"1","head_seq":"42","projected_seq":"42"}
Defensive patterns

Strategy: validation

Type guard

function isHubStatusBadDecimalFields(e: unknown): boolean {
  return e instanceof Error && /sync hub status: response requires decimal-string epoch\/head_seq\/projected_seq/i.test(e.message);
}

Try / catch

try { await cloudSync.status(); }
catch (e) { if (isHubStatusBadDecimalFields(e)) { markHubMisconfigured(e.message); return; } throw e; }

Prevention

When it happens

Trigger: The hub returned epoch/head_seq/projected_seq as JSON numbers, omitted one, or sent null/empty. assertCanonicalDecimal would also reject non-canonical strings (leading zeroes, non-base-10), but the typeof guard catches the non-string cases first.

Common situations: Hub version that serializes sequences as numbers instead of strings; a field renamed in a hub update; a proxy stripping fields; a hub bug emitting null after an internal error.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/b15aafcd889caed6. Report an issue: GitHub.