bitwarden/server · error · NotFoundException

Unable to get Cloud Billing Sync connection

Error message

Unable to get Cloud Billing Sync connection

What it means

Thrown as a NotFoundException (HTTP 404) by the cloud-billing-sync license-refresh path when the organization has no OrganizationConnection of type CloudBillingSync. The controller looks up connections of that type for the (validated) self-hosted org details and, finding none, treats the missing connection as a not-found resource rather than a permission error.

Source

Thrown at src/Api/Controllers/SelfHosted/SelfHostedOrganizationLicensesController.cs:121

    public async Task SyncLicenseAsync(string id)
    {
        var selfHostedOrganizationDetails = await _organizationRepository.GetSelfHostedOrganizationDetailsById(new Guid(id));
        if (selfHostedOrganizationDetails == null)
        {
            throw new NotFoundException();
        }

        if (!await _currentContext.OrganizationOwner(selfHostedOrganizationDetails.Id))
        {
            throw new NotFoundException();
        }

        var billingSyncConnection =
            (await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(selfHostedOrganizationDetails.Id,
                OrganizationConnectionType.CloudBillingSync)).FirstOrDefault();
        if (billingSyncConnection == null)
        {
            throw new NotFoundException("Unable to get Cloud Billing Sync connection");
        }

        var license =
            await _getSelfHostedOrganizationLicenseQuery.GetLicenseAsync(selfHostedOrganizationDetails, billingSyncConnection);
        var currentOrganization = await _organizationRepository.GetByLicenseKeyAsync(license.LicenseKey);

        await _updateOrganizationLicenseCommand.UpdateLicenseAsync(selfHostedOrganizationDetails, license, currentOrganization);

        var config = billingSyncConnection.GetConfig<BillingSyncConfig>();
        config.LastLicenseSync = DateTime.Now;
        billingSyncConnection.SetConfig(config);
        await _organizationConnectionRepository.ReplaceAsync(billingSyncConnection);
    }
}

View on GitHub (pinned to e93b962371)

Solutions

  1. Create an OrganizationConnection of type CloudBillingSync for this organization in the web vault before refreshing.
  2. Confirm the connection is active and its BillingSyncConfig is populated (API key, etc.).
  3. Verify you are operating on the correct org id that owns the connection.
  4. Re-establish the connection if it was deleted and retry the refresh.

Example fix

// before: refresh with no CloudBillingSync connection -> 404
//   await UpdateLicenseSyncAsync(orgId);
//
// after: ensure connection exists first
var conn = await GetCloudBillingSyncConnection(orgId);
if (conn == null) {
  await CreateCloudBillingSyncConnection(orgId, billingSyncApiKey);
}
await UpdateLicenseSyncAsync(orgId);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure a CloudBillingSync connection exists before refreshing the license
const conns = await getOrgConnections(orgId, 'CloudBillingSync');
if (conns.length === 0) {
  await createCloudBillingSyncConnection(orgId, billingSyncApiKey);
}
await refreshLicenseSync(orgId);

Type guard

function hasCloudBillingSyncConnection(list) {
  return Array.isArray(list) && list.some(c => c.type === 'CloudBillingSync' && c.enabled);
}

Try / catch

try {
  await refreshLicenseSync(orgId);
} catch (e) {
  if (e.status === 404 && /billing sync connection/i.test(e.message)) {
    await createCloudBillingSyncConnection(orgId, billingSyncApiKey);
    await refreshLicenseSync(orgId); // one retry after setup
  } else throw e;
}

Prevention

When it happens

Trigger: Triggering a license sync/refresh for a self-hosted org that has not yet configured a Cloud Billing Sync organization connection, or whose connection was deleted. Caller is already verified as the org owner.

Common situations: Org admin sets up license sync but never created the CloudBillingSync connection in the web vault; connection was removed; wrong org selected; migration where the connection did not carry over.

Related errors


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