{"record":{"id":"e27972a1be688ed7","repo":"schollz/croc","slug":"stored-transfers-can-allow-at-most-settings-maxd","errorCode":null,"errorMessage":"Stored transfers can allow at most ${settings.maxDownloads} downloads","messagePattern":"Stored transfers can allow at most (.+?) downloads","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"web/src/protocol/stored.ts","lineNumber":579,"sourceCode":"  settings: StoredSettings;\n  downloads?: number;\n  expiresSeconds?: number;\n  callbacks?: StoredUploadCallbacks;\n  signal?: AbortSignal;\n}) {\n  const {\n    files,\n    settings,\n    downloads = 1,\n    expiresSeconds = 24 * 60 * 60,\n    callbacks = {},\n    signal,\n  } = options;\n  if (!Number.isSafeInteger(downloads) || downloads < 1) {\n    throw new Error(\"Stored-transfer downloads must be a positive integer\");\n  }\n  if (downloads > settings.maxDownloads) {\n    throw new Error(\n      `Stored transfers can allow at most ${settings.maxDownloads} downloads`,\n    );\n  }\n  if (\n    !Number.isSafeInteger(expiresSeconds) ||\n    expiresSeconds < 60 ||\n    expiresSeconds > 9_223_372_036\n  ) {\n    throw new Error(\n      \"Stored-transfer expiration must be a whole number of seconds of at least one minute\",\n    );\n  }\n  if (\n    settings.maxExpiresSeconds > 0 &&\n    expiresSeconds > settings.maxExpiresSeconds\n  ) {\n    throw new Error(\n      `Stored transfers can expire after at most ${settings.maxExpiresSeconds} seconds`,","sourceCodeStart":561,"sourceCodeEnd":597,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/stored.ts#L561-L597","documentation":"Thrown by uploadStoredFiles() (stored.ts:578) when the requested `downloads` count exceeds the ceiling the storage service advertised in settings.maxDownloads. The settings object comes from the store runtime (App.tsx computes `storeRuntime.maxDownloads || 1`), so the limit varies per deployment and defaults to 1.","triggerScenarios":"Calling uploadStoredFiles with downloads > settings.maxDownloads, e.g. downloads: 10 when the service configures maxDownloads: 3. Happens when the UI allows more downloads than the server permits or the settings object is hardcoded/stale.","commonSituations":"Server operator lowered maxDownloads after the UI shipped; reusing a settings object across dev/prod environments; tests running against settings fixtures with a different cap than production.","solutions":["Clamp the request: Math.min(requested, settings.maxDownloads)","Render the UI picker's max from settings.maxDownloads so users cannot over-request","Fetch settings from the live service configuration instead of hardcoding"],"exampleFix":"// before\nawait uploadStoredFiles({ files, settings, downloads: userChoice });\n\n// after\nconst downloads = Math.min(userChoice, settings.maxDownloads);\nawait uploadStoredFiles({ files, settings, downloads });","handlingStrategy":"validation","validationCode":"const downloads = Math.min(Math.max(1, requested), settings.maxDownloads);","typeGuard":"function withinDownloadLimit(downloads: number, s: StoredSettings): boolean {\n  return downloads >= 1 && downloads <= s.maxDownloads;\n}","tryCatchPattern":"try { await uploadStoredFiles(opts); } catch (e) { if (e instanceof Error && e.message.startsWith('Stored transfers can allow at most')) { opts.downloads = settings.maxDownloads; return uploadStoredFiles(opts); } throw e; }","preventionTips":["Set the picker's max attribute to settings.maxDownloads","Treat runtime settings as the single source of truth for limits"],"tags":["validation","stored-transfer","configuration","upload"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}