{"record":{"id":"c99d1c29c0cbafb3","repo":"fullstackhero/dotnet-starter-kit","slug":"file-exceeds-max-size-of-category-maxbytes-bytes-for","errorCode":null,"errorMessage":"File exceeds max size of {category.MaxBytes} bytes for category '{cmd.Category}'.","messagePattern":"File exceeds max size of (.+?) bytes for category '(.+?)'\\.","errorType":"exception","errorClass":"CustomException","httpStatus":400,"severity":"error","filePath":"src/Modules/Files/Modules.Files/Features/v1/RequestUploadUrl/RequestUploadUrlCommandHandler.cs","lineNumber":56,"sourceCode":"        // Category lookup + extension/size validation.\n        if (!options.Value.Categories.TryGetValue(cmd.Category, out var category))\n        {\n            throw new CustomException($\"Unknown category '{cmd.Category}'.\", (IEnumerable<string>?)null, HttpStatusCode.BadRequest);\n        }\n\n        var extension = Path.GetExtension(cmd.FileName);\n        if (string.IsNullOrWhiteSpace(extension) ||\n            !category.AllowedExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))\n        {\n            throw new CustomException(\n                $\"Extension '{extension}' not allowed for category '{cmd.Category}'.\",\n                (IEnumerable<string>?)null,\n                HttpStatusCode.BadRequest);\n        }\n\n        if (cmd.SizeBytes > category.MaxBytes)\n        {\n            throw new CustomException(\n                $\"File exceeds max size of {category.MaxBytes} bytes for category '{cmd.Category}'.\",\n                (IEnumerable<string>?)null,\n                HttpStatusCode.BadRequest);\n        }\n\n        // Authorization: policy must exist and allow the attach.\n        var policy = policies.Resolve(cmd.OwnerType)\n            ?? throw new ForbiddenException($\"No file access policy registered for owner type '{cmd.OwnerType}'.\");\n        if (!await policy.CanAttachAsync(cmd.OwnerId, userId.ToString(), cancellationToken).ConfigureAwait(false))\n        {\n            throw new ForbiddenException(\"Not allowed to attach files to this owner.\");\n        }\n\n        // Quota pre-check (no debit yet — debit happens on finalize with actual bytes).\n        var quotaCheck = await quotas.CheckAsync(tenantId, QuotaResource.StorageBytes, cmd.SizeBytes, cancellationToken).ConfigureAwait(false);\n        if (!quotaCheck.Allowed)\n        {\n            throw new CustomException(","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Files/Modules.Files/Features/v1/RequestUploadUrl/RequestUploadUrlCommandHandler.cs#L38-L74","documentation":"CustomException (BadRequest) thrown when cmd.SizeBytes exceeds category.MaxBytes for the requested category. The handler pre-checks the declared size before issuing a presigned URL so oversized uploads never reach storage.","triggerScenarios":"RequestUploadUrlCommand whose client-declared SizeBytes is greater than the configured max for that category — e.g. a 20 MB file against a 5 MB avatar limit, or an int/byte-unit mistake where the client reports bytes but computed megabytes (or vice versa).","commonSituations":"Users selecting large images/videos for a size-capped category; client computing size incorrectly (MB vs MiB, bits vs bytes) and over-reporting; category MaxBytes lowered in config while clients still offer large files; reporting the compressed size while category limits assume another baseline.","solutions":["Upload a smaller file or compress/resize it so the declared size is within category.MaxBytes.","If the limit is too strict for real use, raise the category's MaxBytes in the Files options configuration.","Fix client size computation to report true byte count (e.g. file.size from the browser File API).","Validate size client-side before calling the API and show the allowed maximum to the user."],"exampleFix":"// before\nawait requestUploadUrl({ category: \"avatar\", sizeBytes: file.size, ... }); // file.size = 25_165_824 > 5 MB limit\n// after\nif (file.size > 5 * 1024 * 1024) showError(\"Max 5 MB\");\nawait requestUploadUrl({ category: \"avatar\", sizeBytes: file.size, ... });","handlingStrategy":"validation","validationCode":"if (file.size > category.maxBytes) throw new Error(`Max ${category.maxBytes} bytes for ${category.name}`);","typeGuard":null,"tryCatchPattern":"try { await requestUploadUrl(cmd); } catch (e) { if (e.status === 400 && e.message?.includes(\"exceeds max size\")) { showToast(`File too large — limit is ${e.maxBytes} bytes`); } else throw e; }","preventionTips":["Check file.size in the browser before calling the API and show the limit in the UI.","Report size with file.size (bytes) — never compute from MB approximations.","Surface per-category limits to users in the upload dialog."],"tags":["validation","files","quota"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}