{"record":{"id":"749a3816a31be019","repo":"fullstackhero/dotnet-starter-kit","slug":"unknown-category-cmd-category","errorCode":null,"errorMessage":"Unknown category '{cmd.Category}'.","messagePattern":"Unknown category '(.+?)'\\.","errorType":"exception","errorClass":"CustomException","httpStatus":400,"severity":"error","filePath":"src/Modules/Files/Modules.Files/Features/v1/RequestUploadUrl/RequestUploadUrlCommandHandler.cs","lineNumber":41,"sourceCode":"    ICurrentUser currentUser,\n    IOptions<FilesOptions> options)\n    : ICommandHandler<RequestUploadUrlCommand, PresignedUploadResponse>\n{\n    public async ValueTask<PresignedUploadResponse> Handle(RequestUploadUrlCommand cmd, CancellationToken cancellationToken)\n    {\n        ArgumentNullException.ThrowIfNull(cmd);\n\n        var tenantId = currentUser.GetTenant() ?? throw new UnauthorizedException(\"invalid tenant\");\n        var userId = currentUser.GetUserId();\n        if (userId == Guid.Empty)\n        {\n            throw new UnauthorizedException(\"no current user\");\n        }\n\n        // 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);","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Files/Modules.Files/Features/v1/RequestUploadUrl/RequestUploadUrlCommandHandler.cs#L23-L59","documentation":"CustomException with HttpStatusCode.BadRequest thrown when cmd.Category is not a key in FilesOptions.Categories. The set of legal categories (e.g. avatar, attachment) is configured via options binding, and the handler refuses any category string it cannot resolve to a configured category definition.","triggerScenarios":"Posting RequestUploadUrlCommand with a category value that is not registered in configuration (e.g. typo 'avatars' vs 'avatar', wrong casing if the options dictionary is case-sensitive, or a category removed from appsettings/env config).","commonSituations":"Client hardcoded a category that the deployment's Files:Categories config does not define; config section renamed or not bound (missing Files options registration); environments (staging/prod) configured with fewer categories than the frontend offers; category string passed with different casing or trailing whitespace.","solutions":["Use a category that exists in the configured Files:Categories section (check appsettings/environment for exact keys).","Add the missing category to configuration under the Files options (name, allowed extensions, max bytes) if it is a legitimate new category.","Trim/normalize the category string on the client and match the configured casing exactly.","Add a FluentValidation rule on RequestUploadUrlCommandValidator to reject unknown categories with a clear message before the handler runs."],"exampleFix":"// before\nawait requestUploadUrl({ category: \"avatars\", ... }); // not configured\n// after\nawait requestUploadUrl({ category: \"avatar\", ... }); // matches Files:Categories:avatar in appsettings","handlingStrategy":"validation","validationCode":"const allowed = [\"avatar\", \"attachment\"]; // mirror of Files:Categories keys\nif (!allowed.includes(category)) throw new Error(`Unknown category '${category}'`);","typeGuard":null,"tryCatchPattern":"try { await requestUploadUrl(cmd); } catch (e) { if (e.status === 400 && e.message?.startsWith(\"Unknown category\")) { showToast(\"Selected file category is not available\"); } else throw e; }","preventionTips":["Source category options from configuration/API, never hardcode in the client.","Sync the accepted category list across environments when config changes.","Add a server-side validator for category values so failures fail fast with a clear message."],"tags":["validation","configuration","files"],"backgroundTag":"invalid-enum-value","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"}