{"record":{"id":"e14c060ee5584f90","repo":"schollz/croc","slug":"storage-service-returned-an-invalid-claim-capabili","errorCode":null,"errorMessage":"Storage service returned an invalid claim capability","messagePattern":"Storage service returned an invalid claim capability","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"web/src/protocol/stored.ts","lineNumber":749,"sourceCode":"  inspection: StoredInspection,\n  settings: StoredSettings,\n  signal?: AbortSignal,\n) {\n  try {\n    const existing = sessionStorage.getItem(claimSessionKey(inspection.share.id));\n    if (existing) return existing;\n  } catch {\n    // Session persistence is optional.\n  }\n  const redeem = await wasm().storeRedeemCapability(inspection.share.key);\n  const response = await authorizedFetch(\n    api(settings, `/${inspection.share.id}/claim`),\n    base64URL(redeem),\n    { method: \"POST\", signal },\n  );\n  const claimed = (await response.json()) as { claimToken: string };\n  if (!isCapability(claimed.claimToken)) {\n    throw new Error(\"Storage service returned an invalid claim capability\");\n  }\n  try {\n    sessionStorage.setItem(claimSessionKey(inspection.share.id), claimed.claimToken);\n  } catch {\n    // The claim remains valid in memory.\n  }\n  return claimed.claimToken;\n}\n\ntype StoredReceiveSession = {\n  inspection: StoredInspection;\n  settings: StoredSettings;\n  callbacks: ReceiveCallbacks;\n  signal?: AbortSignal;\n  claimToken: string;\n  totalBytes: number;\n};\n","sourceCodeStart":731,"sourceCodeEnd":767,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/stored.ts#L731-L767","documentation":"Thrown after POST /{share.id}/claim: the HTTP request succeeded but the JSON body's claimToken failed the isCapability() format check (stored.ts:118). The claim token is a capability string authorizing subsequent downloads; rejecting a malformed one up front prevents confusing failures later in the download flow.","triggerScenarios":"claimStored() gets a 2xx whose parsed body has claimToken undefined, empty, or not a valid base64URL capability. Causes: service version mismatch changing the response shape (e.g. `token` vs `claimToken`), a proxy rewriting the body, or a server bug.","commonSituations":"Storage service upgraded with a new claim schema while the browser runs a cached old web bundle; API gateway/CDN mangling JSON; pointing the web app at an incompatible or mocked backend.","solutions":["Verify service and web client versions match (endpoint must return { claimToken: <capability> })","Hard-refresh / cache-bust the web bundle after a service upgrade","Check that intermediaries (proxy/CDN) pass response bodies through unmodified","If you operate the server, log the actual claim response and align field names"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isClaimResponse(v: unknown): v is { claimToken: string } {\n  const r = v as Record<string, unknown>;\n  return typeof r?.claimToken === 'string' && r.claimToken.length > 0;\n}","tryCatchPattern":"try { await receiveStoredTransfer(others); } catch (e) { if (e instanceof Error && e.message === 'Storage service returned an invalid claim capability') { reportServiceVersionMismatch(); return; } throw e; }","preventionTips":["Deploy web client and storage service together; cache-bust after upgrades","Smoke-test the claim endpoint after each service deploy"],"tags":["stored-transfer","api-contract","download","server-mismatch"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}