schollz/croc · error
Storage service returned an invalid upload capability
Error message
Storage service returned an invalid upload capability
What it means
The upload token returned by the create endpoint must be a capability: exactly 32 bytes of opaque data in canonical unpadded base64url (isCapability() round-trips the encoding to reject padded or non-canonical forms). A missing, wrong-length, or non-canonical uploadToken throws before any bytes are uploaded.
Source
Thrown at web/src/protocol/stored.ts:445
plaintextBytes: plan.totalSize,
...(downloads === 1 ? {} : { downloads }),
...(expiresSeconds === 24 * 60 * 60 ? {} : { expiresSeconds }),
}),
});
if (!response.ok) throw await responseError(response);
const created = (await response.json()) as {
id: string;
uploadToken: string;
uploadExpiresAt: string;
chunkSize: number;
};
if (created.chunkSize !== storedChunkSize) {
throw new Error(
`Storage service returned unsupported chunk size ${created.chunkSize}`,
);
}
if (!isCapability(created.uploadToken)) {
throw new Error("Storage service returned an invalid upload capability");
}
const downloadsHeader = response.headers.get("X-Croc-Downloads");
const acceptedDownloads =
downloadsHeader === null ? 1 : Number(downloadsHeader);
if (!Number.isSafeInteger(acceptedDownloads) || acceptedDownloads < 1) {
throw new Error("Storage service returned an invalid download count");
}
if (acceptedDownloads !== downloads) {
throw new Error(
`Storage service created ${acceptedDownloads} downloads instead of ${downloads}`,
);
}
return {
share: validateShare({
origin: window.location.origin,
id: created.id,
key,
}),View on GitHub (pinned to e25f1bdc04)
Solutions
- Run a matching-version storage service that returns a 32-byte base64url capability as uploadToken
- Remove any middleware that rewrites or re-serializes the /transfers response body
- Inspect the raw create response (curl) to see what uploadToken actually contains
Defensive patterns
Strategy: try-catch
Try / catch
try { return await createStoredUpload(...); } catch (e) { if (e instanceof Error && e.message.includes("upload capability")) { logServerContractViolation("uploadToken"); } throw e; } Prevention
- Verify your storage service returns a 32-byte base64url capability for uploadToken
- Avoid middleboxes that re-encode response bodies on /transfers endpoints
When it happens
Trigger: created.uploadToken is undefined/short/padded or not valid base64url — a server implementation that returns a JWT or session string instead of the 32-byte capability, or a proxy that rewrites the JSON body.
Common situations: Third-party / incompatible storage backends; API gateways that decode/re-encode response bodies; version skew where the token format changed.
Related errors
- Invalid stored-transfer id
- Storage service returned unsupported chunk size ${created.ch
- Storage service returned an invalid download count
- Storage service created ${acceptedDownloads} downloads inste
- Storage service returned an invalid expiration time
AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15).
Data as JSON: /api/errors/9e32eebda83b6022.
Report an issue: GitHub.