bitwarden/server · error · BadRequestException

Cannot verify license file.

Error message

Cannot verify license file.

What it means

Thrown by ValidateBillingSyncConfig when ReadOrganizationLicenseAsync returns null (no license file for the org) or VerifyLicense returns false (signature invalid / expired / tampered). Billing Sync requires a valid organization license to derive the CloudOrganizationId, so a missing or unverifiable license blocks connection creation. Maps to HTTP 400.

Source

Thrown at src/Api/AdminConsole/Controllers/OrganizationConnectionsController.cs:205

        }
        return type switch
        {
            OrganizationConnectionType.Scim => await _currentContext.ManageScim(organizationId.Value),
            _ => await _currentContext.OrganizationOwner(organizationId.Value),
        };
    }

    private async Task ValidateBillingSyncConfig(OrganizationConnectionRequestModel<BillingSyncConfig> typedModel)
    {
        if (!_globalSettings.SelfHosted)
        {
            throw new BadRequestException($"Cannot create a {typedModel.Type} connection outside of a self-hosted instance.");
        }
        var license = await _licensingService.ReadOrganizationLicenseAsync(typedModel.OrganizationId);

        if (license == null || !_licensingService.VerifyLicense(license))
        {
            throw new BadRequestException("Cannot verify license file.");
        }
        typedModel.ParsedConfig.CloudOrganizationId = license.Id;
    }

    private async Task<OrganizationConnectionResponseModel> CreateOrUpdateOrganizationConnectionAsync<T>(
        Guid? organizationConnectionId,
        OrganizationConnectionRequestModel model,
        Func<OrganizationConnectionRequestModel<T>, Task>? validateAction = null)
        where T : IConnectionConfig
    {
        var typedModel = new OrganizationConnectionRequestModel<T>(model);
        if (validateAction != null)
        {
            await validateAction(typedModel);
        }

        var data = typedModel.ToData(organizationConnectionId);
        var connection = organizationConnectionId.HasValue

View on GitHub (pinned to e93b962371)

Solutions

  1. Generate and install a valid organization license (from the cloud org owner portal) onto the self-hosted instance.
  2. Renew an expired license and reinstall the new file.
  3. Verify the server's system clock is correct (NTP) so license expiry/signature checks pass.
  4. Confirm the licensing public key configured on the server matches the key that signed the license.
  5. Check that ReadOrganizationLicenseAsync can locate the license file path for the org.
Defensive patterns

Strategy: validation

Validate before calling

// Ensure a valid org license is installed before creating BillingSync
var license = await licensingService.ReadOrganizationLicenseAsync(orgId);
if (license == null) throw new InvalidOperationException("No organization license installed.");
if (!licensingService.VerifyLicense(license)) throw new InvalidOperationException("License failed verification.");

Try / catch

try { await client.PostAsync("organizations/connections", billingSyncBody); }
catch (ApiException ex) when (ex.Message.Contains("Cannot verify license")) {
    // prompt admin to install/renew the org license, then retry
}

Prevention

When it happens

Trigger: POST/PUT a CloudBillingSync connection when the organization has no installed license file on the self-hosted server, or the installed license is expired, revoked, signed by an untrusted key, or corrupted.

Common situations: License never installed on the self-hosted instance; license expired and not renewed; server clock skew causing signature/expiry validation failure; license file corrupted during transfer; wrong signing key configured on the server.

Related errors


AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13). Data as JSON: /api/errors/7553491bf65637c2. Report an issue: GitHub.