{"record":{"id":"a326322630fc7e7c","repo":"schollz/croc","slug":"storage-service-returned-an-invalid-remaining-down","errorCode":null,"errorMessage":"Storage service returned an invalid remaining-download count","messagePattern":"Storage service returned an invalid remaining-download count","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"web/src/protocol/stored.ts","lineNumber":886,"sourceCode":"      if (\n        (error instanceof DOMException && error.name === \"AbortError\") ||\n        (error instanceof StoredHTTPError && error.status < 500)\n      ) {\n        throw error;\n      }\n      await new Promise((resolve) =>\n        window.setTimeout(resolve, (attempt + 1) * 250),\n      );\n    }\n  }\n  if (!response) throw lastError;\n  forgetClaim(inspection.share.id);\n  forgetVerifiedDownload(inspection.share.id);\n  const header = response.headers.get(\"X-Croc-Downloads-Remaining\");\n  if (header === null) return 0;\n  const remaining = Number(header);\n  if (!Number.isSafeInteger(remaining) || remaining < 0) {\n    throw new Error(\n      \"Storage service returned an invalid remaining-download count\",\n    );\n  }\n  return remaining;\n}\n\nexport async function receiveStoredTransfer(options: {\n  inspection: StoredInspection;\n  settings: StoredSettings;\n  callbacks: ReceiveCallbacks;\n  signal?: AbortSignal;\n}) {\n  const { inspection, settings, callbacks, signal } = options;\n\n  if (hasVerifiedDownload(inspection.share.id)) {\n    const session: StoredReceiveSession = {\n      inspection,\n      settings,","sourceCodeStart":868,"sourceCodeEnd":904,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/stored.ts#L868-L904","documentation":"Thrown after a successful chunk download: the X-Croc-Downloads-Remaining response header is present but is not a non-negative safe integer. The header reports how many downloads remain before deletion; a missing header is treated as 0, but a present-and-malformed value (empty, 'abc', '-1', '1.5') is a protocol violation.","triggerScenarios":"The download request succeeds but a reverse proxy, CDN, or the service emits a corrupted X-Croc-Downloads-Remaining header: present yet empty or non-numeric. headers.get() is case-insensitive, so the issue is always the value, not casing.","commonSituations":"nginx/Cloudflare rewriting or padding custom headers; a partially deployed service version that sets the header inconsistently across code paths.","solutions":["Reproduce with curl -i against the service to see the actual header value","Fix or disable proxy header rewriting for this endpoint","Upgrade the storage service so it always emits a valid integer header or omits it entirely"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isValidRemainingHeader(v: string | null): boolean {\n  if (v === null) return true;\n  return /^\\d+$/.test(v) && Number.isSafeInteger(Number(v));\n}","tryCatchPattern":"try { await commitStoredDownload(session); } catch (e) { if (e instanceof Error && e.message.includes('invalid remaining-download count')) { logHeaderDiagnostics(); markRemainingUnknown(); return; } throw e; }","preventionTips":["Ensure proxies pass X-Croc-Downloads-Remaining through untouched","Treat this as a service/proxy defect; do not blind-retry the download"],"tags":["stored-transfer","http-headers","protocol","download"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}