{"record":{"id":"2052f4a4a376ad2c","repo":"bitwarden/server","slug":"no-license-to-generate","errorCode":null,"errorMessage":"No license to generate.","messagePattern":"No license to generate\\.","errorType":"exception","errorClass":"Exception","httpStatus":500,"severity":"error","filePath":"src/Admin/Controllers/ToolsController.cs","lineNumber":337,"sourceCode":"            var license = await _getCloudOrganizationLicenseQuery.GetLicenseAsync(organization,\n                model.InstallationId.Value, model.Version);\n            var ms = new MemoryStream();\n            await JsonSerializer.SerializeAsync(ms, license, JsonHelpers.Indented);\n            ms.Seek(0, SeekOrigin.Begin);\n            return File(ms, \"text/plain\", \"bitwarden_organization_license.json\");\n        }\n        else if (user != null)\n        {\n            var license = await _userService.GenerateLicenseAsync(user, null, model.Version);\n            var ms = new MemoryStream();\n            ms.Seek(0, SeekOrigin.Begin);\n            await JsonSerializer.SerializeAsync(ms, license, JsonHelpers.Indented);\n            ms.Seek(0, SeekOrigin.Begin);\n            return File(ms, \"text/plain\", \"bitwarden_premium_license.json\");\n        }\n        else\n        {\n            throw new Exception(\"No license to generate.\");\n        }\n    }\n}\n","sourceCodeStart":319,"sourceCodeEnd":341,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Admin/Controllers/ToolsController.cs#L319-L341","documentation":"Thrown in the GenerateLicense action when neither a valid user nor a valid organization was resolved from the submitted model. The code checks model.UserId and model.OrganizationId, loads the respective entity, and if both are null/unset (and ModelState is otherwise valid), this else-branch fires. It indicates the form was submitted with neither a user ID nor an organization ID.","triggerScenarios":"An admin submits the license generation form without selecting either a user or an organization. This is typically unreachable in the normal UI flow because form validation should catch the empty state, but can be triggered by a direct API call or a client-side validation bypass.","commonSituations":"A direct HTTP POST to the GenerateLicense endpoint with an empty body or a body missing both UserId and OrganizationId. A browser extension or script that bypasses client-side validation. A UI bug that allows submission without selecting a target.","solutions":["Ensure the license generation form has either a UserId or an OrganizationId filled before submission.","Add server-side ModelState validation that at least one of UserId/OrganizationId is required (it appears ModelState may pass when both are null since they are optional fields).","If calling the endpoint programmatically, always include one of the two IDs in the request body.","Consider adding a [Required] attribute on a custom validation property to enforce mutual exclusivity and presence."],"exampleFix":"// before: no validation for at-least-one\n// after: add a model-level validation\nif (!model.UserId.HasValue && !model.OrganizationId.HasValue)\n{\n    ModelState.AddModelError(string.Empty, \"Either User Id or Organization Id is required.\");\n    return View(model);\n}","handlingStrategy":"validation","validationCode":"// Server-side: enforce at least one target before processing\nif (!model.UserId.HasValue && !model.OrganizationId.HasValue)\n{\n    ModelState.AddModelError(string.Empty, \"Either User Id or Organization Id is required.\");\n    return View(model);\n}","typeGuard":"static bool HasLicenseTarget(LicenseModel model)\n    => model.UserId.HasValue || model.OrganizationId.HasValue;","tryCatchPattern":null,"preventionTips":["Add a custom validation attribute (IValidatableObject) on LicenseModel to enforce mutual presence.","Disable the submit button client-side until either a user or org is selected.","Add an integration test that posts a model with neither ID and asserts a validation error (not a 500)."],"tags":["admin","tools","licensing","validation"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}