{"record":{"id":"19632b8749f49019","repo":"thedotmack/claude-mem","slug":"status-res-status-await-res-text-catch-slice-0-200","errorCode":null,"errorMessage":"status ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 200)}","messagePattern":"status (.+?): (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"workers/sync-hub/canary/canary.ts","lineNumber":278,"sourceCode":"\t\tif (!res.ok) {\n\t\t\tthrow new Error(`pull ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 200)}`);\n\t\t}\n\t\tconst parsed = (await res.json()) as {\n\t\t\tops: Array<{ seq: string; operation_sha256: string }>;\n\t\t\thead_seq: string;\n\t\t};\n\t\treturn { ops: parsed.ops, headSeq: parsed.head_seq };\n\t}\n\n\t/** Start both cursors at the current head — only NEW ops matter. */\n\tasync init(): Promise<void> {\n\t\tconst res = await fetch(`${this.args.hub}/v1/sync/status`, {\n\t\t\theaders: this.headers(DEVICE_A),\n\t\t\tsignal: AbortSignal.timeout(this.args.timeoutMs),\n\t\t});\n\t\tthis.noteMode(res);\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(`status ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 200)}`);\n\t\t}\n\t\tconst status = (await res.json()) as { head_seq: string; epoch: string };\n\t\tthis.cursors[DEVICE_A] = String(status.head_seq);\n\t\tthis.cursors[DEVICE_B] = String(status.head_seq);\n\t\tlog({\n\t\t\tevent: \"init\",\n\t\t\thub: this.args.hub,\n\t\t\tuser: this.args.user,\n\t\t\thead_seq: status.head_seq,\n\t\t\tepoch: status.epoch,\n\t\t\tsync_mode: this.syncMode,\n\t\t});\n\t}\n\n\t/**\n\t * One trickle cycle: origin pushes a tiny op; the OTHER device polls its\n\t * cursor forward until it sees that exact op (or the bound expires).\n\t */","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/workers/sync-hub/canary/canary.ts#L260-L296","documentation":"Thrown by the canary's `init` method when the `/v1/sync/status` health/bootstrap endpoint returns a non-2xx status, with the HTTP status and the first 200 bytes of the body included in the message. Because `init` is the first hub call of a canary run (called from `main`), this error typically means the run aborts immediately: the hub is unreachable, misconfigured, or refusing authentication.","triggerScenarios":"Any `fetch(`${hub}/v1/sync/status`)` response with `res.ok === false`: 401 for a missing/invalid DEVICE_A token, 404 when the hub route isn't deployed or the URL is wrong, 5xx when the hub worker or its database (D1) is down, or 429 rate limiting on a shared worker.","commonSituations":"Canary started before a hub deploy finished (route not yet live); hub URL env var points at staging vs production; device tokens rotated but canary secrets not updated; hub's D1 binding broken after a wrangler config change.","solutions":["Check the embedded status: 401 → update the device token secrets; 404 → fix the hub URL / redeploy the worker; 5xx → inspect hub logs and D1 health.","Curl `/v1/sync/status` manually with the same headers to confirm whether the problem is hub-side or canary-side.","Add a short retry with backoff for transient 5xx/429 before failing `main`.","Confirm wrangler deploy of the sync-hub worker completed and the route matches `this.args.hub`."],"exampleFix":"// before\nif (!res.ok) {\n  throw new Error(`status ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 200)}`);\n}\n\n// after\nif (!res.ok) {\n  const body = await res.text().catch(() => \"\");\n  if (res.status >= 500 || res.status === 429) return this.retryInit();\n  throw new Error(`status ${res.status}: ${body.slice(0, 200)}`);\n}","handlingStrategy":"try-catch","validationCode":"// pre-flight check before running the canary\nasync function assertHubReady(hub: string, headers: HeadersInit) {\n  const res = await fetch(`${hub}/v1/sync/status`, { headers, signal: AbortSignal.timeout(5000) });\n  if (!res.ok) throw new Error(`hub not ready: ${res.status}; fix config before starting canary`);\n}","typeGuard":"function isStatusPayload(res: unknown): res is { head_seq: string; epoch: string } {\n  const r = res as any;\n  return r && typeof r.head_seq !== 'undefined' && typeof r.epoch !== 'undefined';\n}","tryCatchPattern":"try {\n  await canary.init();\n} catch (err) {\n  if (err instanceof Error && /^status \\d{3}:/.test(err.message)) {\n    const status = Number(err.message.slice(7, 10));\n    if (status === 401 || status === 403) console.error('check device token secrets');\n    if (status === 404) console.error('check hub URL / deployment');\n    process.exitCode = 1; // init failure aborts the whole run\n  } else throw err;\n}","preventionTips":["Run a pre-flight health check on /v1/sync/status before scheduling canary runs.","Keep canary device-token secrets in sync with hub token rotations.","Verify post-deploy smoke tests cover the status endpoint before the canary cron fires.","Pin the hub URL per environment and validate it at startup."],"tags":["http","network","initialization","error-response"],"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"}