schollz/croc · error
Stored-transfer downloads must be a positive integer
Error message
Stored-transfer downloads must be a positive integer
What it means
Thrown by uploadStoredFiles() (web/src/protocol/stored.ts:575) when the `downloads` option is not a safe positive integer. The library validates client-side before any network call because the storage service only permits whole download counts starting at 1. Values like 0, -1, 2.5, NaN, Infinity, or undefined all fail the Number.isSafeInteger / < 1 checks.
Source
Thrown at web/src/protocol/stored.ts:576
export async function uploadStoredFiles(options: {
files: StoredPreparedFile[];
settings: StoredSettings;
downloads?: number;
expiresSeconds?: number;
callbacks?: StoredUploadCallbacks;
signal?: AbortSignal;
}) {
const {
files,
settings,
downloads = 1,
expiresSeconds = 24 * 60 * 60,
callbacks = {},
signal,
} = options;
if (!Number.isSafeInteger(downloads) || downloads < 1) {
throw new Error("Stored-transfer downloads must be a positive integer");
}
if (downloads > settings.maxDownloads) {
throw new Error(
`Stored transfers can allow at most ${settings.maxDownloads} downloads`,
);
}
if (
!Number.isSafeInteger(expiresSeconds) ||
expiresSeconds < 60 ||
expiresSeconds > 9_223_372_036
) {
throw new Error(
"Stored-transfer expiration must be a whole number of seconds of at least one minute",
);
}
if (
settings.maxExpiresSeconds > 0 &&
expiresSeconds > settings.maxExpiresSecondsView on GitHub (pinned to e25f1bdc04)
Solutions
- Validate/clamp before the call: whole number >= 1 (the option defaults to 1, so omit it when unsure)
- Derive from UI input with Math.max(1, Math.floor(value)) and re-check Number.isSafeInteger
- Type-guard values deserialized from JSON before passing them into options
Example fix
// before
await uploadStoredFiles({ files, settings, downloads: Number(input.value) });
// after
const downloads = Number(input.value);
if (!Number.isSafeInteger(downloads) || downloads < 1) throw new RangeError('downloads must be a whole number >= 1');
await uploadStoredFiles({ files, settings, downloads }); Defensive patterns
Strategy: validation
Validate before calling
const downloads = Number(raw);
if (!Number.isSafeInteger(downloads) || downloads < 1) {
throw new RangeError(`downloads must be a whole number >= 1, got ${raw}`);
} Type guard
function isValidDownloadCount(v: unknown): v is number {
return typeof v === 'number' && Number.isSafeInteger(v) && v >= 1;
} Try / catch
try { await uploadStoredFiles(opts); } catch (e) { if (e instanceof Error && e.message === 'Stored-transfer downloads must be a positive integer') { flagField('downloads'); return; } throw e; } Prevention
- Clamp UI values with Math.floor and a >=1 floor before submit
- Type-guard anything deserialized from JSON before it reaches options
When it happens
Trigger: Calling uploadStoredFiles({ files, settings, downloads: X }) with X = 0, negative, fractional (e.g. 1.5), NaN, Infinity, or undefined/non-number. Typical when the value comes from a UI slider defaulting to 0, from parseInt of user input, or from untyped deserialized JSON.
Common situations: A number-of-downloads picker whose default is 0 before the user selects; reading the field out of localStorage/sessionStorage receipts where it may be missing; passing a string like '3' (Number.isSafeInteger('3') is false).
Related errors
- Stored-transfer expiration must be a whole number of seconds
- Stored transfers can allow at most ${settings.maxDownloads}
- Stored transfers can expire after at most ${settings.maxExpi
- Invalid stored-transfer id
- Stored transfers can contain at most ${settings.maxFiles} fi
AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15).
Data as JSON: /api/errors/154d4b2b40597170.
Report an issue: GitHub.