{"record":{"id":"ab7c6cd7297d24de","repo":"bitwarden/server","slug":"invalid-license-ab7c6c","errorCode":null,"errorMessage":"Invalid license","messagePattern":"Invalid license","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Api/Controllers/SelfHosted/SelfHostedOrganizationLicensesController.cs","lineNumber":67,"sourceCode":"        _selfHostedOrganizationSignUpCommand = selfHostedOrganizationSignUpCommand;\n        _organizationRepository = organizationRepository;\n        _userService = userService;\n        _updateOrganizationLicenseCommand = updateOrganizationLicenseCommand;\n    }\n\n    [HttpPost(\"\")]\n    public async Task<OrganizationResponseModel> CreateLicenseAsync(OrganizationCreateLicenseRequestModel model)\n    {\n        var user = await _userService.GetUserByPrincipalAsync(User);\n        if (user == null)\n        {\n            throw new UnauthorizedAccessException();\n        }\n\n        var license = await ApiHelpers.ReadJsonFileFromBody<OrganizationLicense>(HttpContext, model.License);\n        if (license == null)\n        {\n            throw new BadRequestException(\"Invalid license\");\n        }\n\n        var result = await _selfHostedOrganizationSignUpCommand.SignUpAsync(license, user, model.Key,\n            model.CollectionName, model.Keys?.PublicKey, model.Keys?.EncryptedPrivateKey);\n\n        return new OrganizationResponseModel(result.Item1, null);\n    }\n\n    [HttpPost(\"{id}\")]\n    public async Task UpdateLicenseAsync(string id, LicenseRequestModel model)\n    {\n        var orgIdGuid = new Guid(id);\n        if (!await _currentContext.OrganizationOwner(orgIdGuid))\n        {\n            throw new NotFoundException();\n        }\n\n        var license = await ApiHelpers.ReadJsonFileFromBody<OrganizationLicense>(HttpContext, model.License);","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Controllers/SelfHosted/SelfHostedOrganizationLicensesController.cs#L49-L85","documentation":"Thrown by POST /organizations (self-hosted license signup) when the uploaded license file cannot be read into an OrganizationLicense. ApiHelpers.ReadJsonFileFromBody<OrganizationLicense> returns null if the IFormFile is missing, empty, larger than 50 KB (51200 bytes), or not valid OrganizationLicense JSON. The guard therefore rejects any malformed, oversized, or absent license before signup runs.","triggerScenarios":"POST /organizations/licenses with no License file part, an empty upload, a file over 50 KB, a file that is not JSON, or JSON whose schema does not bind to OrganizationLicense (missing required fields, wrong casing).","commonSituations":"Operator exports a license from the cloud instance but the download is truncated or HTML error page; license JSON keys renamed in a newer server version; uploading a UserLicense instead of an OrganizationLicense; file exceeds the 50 KB body cap.","solutions":["Re-export the organization license from the cloud Bitwarden instance and upload the unmodified .json file.","Confirm the file is a OrganizationLicense (not a UserLicense) and matches the installed server version.","Keep the file under 50 KB; if a license legitimately exceeds it, split/regenerate.","Validate the JSON parses and has required fields (LicenseKey, InstallationId, etc.) before uploading."],"exampleFix":"// before: posting the wrong file (user license) or none\n//   form.License = userLicenseFile; // -> null parse -> 400\n//\n// after: post the organization license file as multipart/form-data\nvar form = new FormData();\nform.append(\"license\", organizationLicenseJsonFile, \"license.json\");\nawait fetch('/organizations/licenses', { method: 'POST', body: form });","handlingStrategy":"validation","validationCode":"// Validate the license file client-side before the self-hosted org signup upload\nfunction isValidOrgLicenseFile(file, text) {\n  if (!file || file.size === 0 || file.size > 51200) return false;\n  try { const j = JSON.parse(text); return !!j.licenseKey && !!j.installationId; } catch { return false; }\n}\nconst text = await file.text();\nif (!isValidOrgLicenseFile(file, text)) throw new Error('Invalid organization license');\nawait uploadOrgLicense(file);","typeGuard":"function isOrganizationLicense(j) {\n  return j != null && typeof j === 'object'\n    && typeof j.licenseKey === 'string'\n    && typeof j.installationId === 'string';\n}","tryCatchPattern":"try {\n  await createSelfHostedOrg(licenseFile);\n} catch (e) {\n  if (e.status === 400 && /invalid license/i.test(e.message)) {\n    showOperatorError('Re-export the organization license from the cloud instance and re-upload.');\n  } else throw e;\n}","preventionTips":["Upload the unmodified organization license JSON exported from the cloud instance.","Keep the file under 50 KB; parse and schema-check it before upload.","Use OrganizationLicense (not UserLicense) matching the installed server version."],"tags":["licensing","self-hosted","validation","http-400","file-upload"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}