schollz/croc · error

Storage service returned an invalid remaining-download count

Error message

Storage service returned an invalid remaining-download count

What it means

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.

Source

Thrown at web/src/protocol/stored.ts:886

      if (
        (error instanceof DOMException && error.name === "AbortError") ||
        (error instanceof StoredHTTPError && error.status < 500)
      ) {
        throw error;
      }
      await new Promise((resolve) =>
        window.setTimeout(resolve, (attempt + 1) * 250),
      );
    }
  }
  if (!response) throw lastError;
  forgetClaim(inspection.share.id);
  forgetVerifiedDownload(inspection.share.id);
  const header = response.headers.get("X-Croc-Downloads-Remaining");
  if (header === null) return 0;
  const remaining = Number(header);
  if (!Number.isSafeInteger(remaining) || remaining < 0) {
    throw new Error(
      "Storage service returned an invalid remaining-download count",
    );
  }
  return remaining;
}

export async function receiveStoredTransfer(options: {
  inspection: StoredInspection;
  settings: StoredSettings;
  callbacks: ReceiveCallbacks;
  signal?: AbortSignal;
}) {
  const { inspection, settings, callbacks, signal } = options;

  if (hasVerifiedDownload(inspection.share.id)) {
    const session: StoredReceiveSession = {
      inspection,
      settings,

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Reproduce with curl -i against the service to see the actual header value
  2. Fix or disable proxy header rewriting for this endpoint
  3. Upgrade the storage service so it always emits a valid integer header or omits it entirely
Defensive patterns

Strategy: try-catch

Type guard

function isValidRemainingHeader(v: string | null): boolean {
  if (v === null) return true;
  return /^\d+$/.test(v) && Number.isSafeInteger(Number(v));
}

Try / catch

try { await commitStoredDownload(session); } catch (e) { if (e instanceof Error && e.message.includes('invalid remaining-download count')) { logHeaderDiagnostics(); markRemainingUnknown(); return; } throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: nginx/Cloudflare rewriting or padding custom headers; a partially deployed service version that sets the header inconsistently across code paths.

Related errors


AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15). Data as JSON: /api/errors/a326322630fc7e7c. Report an issue: GitHub.