{"record":{"id":"cd534fd359437340","repo":"JuliusBrussee/caveman","slug":"registration-failed-http-response-status","errorCode":null,"errorMessage":"registration failed: HTTP ${response.status}","messagePattern":"registration failed: HTTP (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/cli.ts","lineNumber":502,"sourceCode":"      agent_slug: lock.agent_id,\n      build_sha256: lock.build_sha256,\n      plan_sha256: lock.plan_sha256,\n      source_sha256: lock.source_sha256,\n      eval_suite_sha256: lock.eval_suite_sha256,\n      catalog_sha256: lock.catalog_sha256,\n      transform_registry_sha256: lock.runtime.transform_registry_sha256,\n      harness: lock.harness.id,\n      adapter_version: lock.harness.adapter_version,\n      upstream_version: lock.harness.upstream_version,\n      runtime_version: lock.runtime.caveman_version,\n      evidence_status: lock.evidence.status,\n      evidence_basis: lock.evidence.basis,\n      lock,\n    }),\n    signal: AbortSignal.timeout(10_000),\n  });\n  if (!response.ok) {\n    throw new Error(`registration failed: HTTP ${response.status}`);\n  }\n  const registered = await response.json() as { id?: unknown; build_sha256?: unknown };\n  process.stdout.write([\n    `registered build: ${String(registered.build_sha256 ?? lock.build_sha256)}`,\n    `registration id: ${String(registered.id ?? \"unavailable\")}`,\n    \"registration does not activate plan or create a savings claim\",\n    \"provider savings: not claimed\",\n    \"\",\n  ].join(\"\\n\"));\n}\n\nasync function dev(args: string[]): Promise<void> {\n  const root = process.cwd();\n  const entry = args[0] ?? \"src/agent.ts\";\n  const prompt = args.slice(1).join(\" \") || \"Reply with one short greeting.\";\n  const conversation = createConversation();\n  const sessionId = conversation.sessionId;\n  const interactive = args.length <= 1 && process.stdin.isTTY && process.stdout.isTTY;","sourceCodeStart":484,"sourceCodeEnd":520,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/cli.ts#L484-L520","documentation":"The POST to {controlURL}/api/v1/projects/{projectID}/agent-builds completed but response.ok was false, so the CLI surfaces the HTTP status verbatim. The request already passed env validation and the stale-lock gate; this is the server rejecting the registration (auth, project id, payload, or server-side error). The fetch has a 10s AbortSignal timeout, which surfaces as an AbortError, not this message.","triggerScenarios":"401/403 from an invalid or expired CAVE_TOKEN; 404 from a wrong CAVE_PROJECT_ID or wrong CAVE_CONTROL_URL base path; 400/409 from an already-registered build_sha256 or schema mismatch after CLI/server version drift; 5xx from a control-plane outage.","commonSituations":"Expired registration token in CI; pointing CAVE_CONTROL_URL at staging while the project lives in prod (or vice versa); re-registering the same build; server API evolved beyond the CLI's payload shape.","solutions":["Decode the status: 401/403 → rotate/refresh CAVE_TOKEN; 404 → verify CAVE_PROJECT_ID and CAVE_CONTROL_URL; 409 → build already registered, nothing to do; 5xx → retry or check the control plane.","Re-check that CAVE_CONTROL_URL is the correct environment base URL with no /api suffix (the CLI appends the path).","If 400 persists, compare CLI and control-plane versions — the payload contract may have moved; upgrade the caveman agent package."],"exampleFix":"# before\nexport CAVE_CONTROL_URL=https://cave.internal   # wrong env (404)\ncaveman-agent register\n\n# after\nexport CAVE_CONTROL_URL=https://cave.example.com\ncaveman-agent register","handlingStrategy":"retry","validationCode":"function registrationTargetPlausible(): { ok: boolean; reason?: string } {\n  const url = process.env.CAVE_CONTROL_URL;\n  if (!url?.startsWith(\"https://\")) return { ok: false, reason: \"CAVE_CONTROL_URL must be an https base URL\" };\n  if (!/^[A-Za-z0-9_-]+$/.test(process.env.CAVE_PROJECT_ID ?? \"\")) return { ok: false, reason: \"CAVE_PROJECT_ID malformed\" };\n  return { ok: true };\n}","typeGuard":null,"tryCatchPattern":"const RETRYABLE = new Set([408, 429, 502, 503, 504]);\nlet attempt = 0;\nwhile (true) {\n  try {\n    return await register(args);\n  } catch (error) {\n    const status = Number((error as Error).message.match(/HTTP (\\d+)/)?.[1]);\n    if (RETRYABLE.has(status) && ++attempt < 4) {\n      await sleep(2 ** attempt * 500); // exponential backoff on 429/5xx only\n      continue;\n    }\n    if (status === 409) return; // already registered — treat as success\n    throw error; // 401/403/404 are config defects, do not retry\n  }\n}","preventionTips":["Verify token freshness and correct environment (staging vs prod) for CAVE_CONTROL_URL before registering.","Handle 409 as idempotent success — re-registering the same build_sha256 is expected after retries.","Keep CLI and control-plane versions aligned; upgrade the agent package when the server API changes."],"tags":["registration","network","http","authentication"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}