bitwarden/server · error · BadRequestException

The requested organization already has a connection of type

Error message

The requested organization already has a connection of type {model.Type}. Only one of each connection type may exist per organization.

What it means

Thrown by OrganizationConnectionsController.CreateConnection (POST /organizations/connections) when HasConnectionTypeAsync finds that the organization already has at least one connection of the same type. The system enforces a one-per-type-per-organization invariant, so the second POST for the same (OrganizationId, Type) pair is rejected. Maps to HTTP 400.

Source

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

    }

    [HttpGet("enabled")]
    public bool ConnectionsEnabled()
    {
        return _globalSettings.SelfHosted && _globalSettings.EnableCloudCommunication;
    }

    [HttpPost]
    public async Task<OrganizationConnectionResponseModel> CreateConnection([FromBody] OrganizationConnectionRequestModel model)
    {
        if (!await HasPermissionAsync(model.OrganizationId, model.Type))
        {
            throw new BadRequestException($"You do not have permission to create a connection of type {model.Type}.");
        }

        if (await HasConnectionTypeAsync(model, null, model.Type))
        {
            throw new BadRequestException($"The requested organization already has a connection of type {model.Type}. Only one of each connection type may exist per organization.");
        }

        switch (model.Type)
        {
            case OrganizationConnectionType.CloudBillingSync:
                return await CreateOrUpdateOrganizationConnectionAsync<BillingSyncConfig>(null, model, ValidateBillingSyncConfig);
            case OrganizationConnectionType.Scim:
                return await CreateOrUpdateOrganizationConnectionAsync<ScimConfig>(null, model);
            default:
                throw new BadRequestException($"Unknown Organization connection Type: {model.Type}");
        }
    }

    [HttpPut("{organizationConnectionId}")]
    public async Task<OrganizationConnectionResponseModel> UpdateConnection(Guid organizationConnectionId, [FromBody] OrganizationConnectionRequestModel model)
    {
        if (model == null)
        {

View on GitHub (pinned to e93b962371)

Solutions

  1. GET the existing connection first (GET /organizations/connections/{organizationId}/{type}) and, if present, use PUT to update it instead of POSTing a new one.
  2. Make the create call idempotent client-side: treat 'already has connection' as success and switch to update flow.
  3. Guard against duplicate submissions with a request deduplication key or disable the submit button until the first call resolves.
  4. If a phantom connection exists from a failed prior attempt, DELETE it before re-creating.

Example fix

// before
await client.PostAsync("organizations/connections", new { orgId, type, config });
// after
var existing = await client.GetAsync($"organizations/connections/{orgId}/{type}");
if (existing.IsSuccessStatusCode)
    await client.PutAsync($"organizations/connections/{existing.Id}", body);
else
    await client.PostAsync("organizations/connections", body);
Defensive patterns

Strategy: validation

Validate before calling

// Check for an existing connection before creating
var existing = await client.GetAsync<OrganizationConnectionResponseModel>(
    $"organizations/connections/{orgId}/{(int)type}");
if (existing != null) {
    // update instead of create
    await client.PutAsync($"organizations/connections/{existing.Id}", body);
    return;
}
await client.PostAsync("organizations/connections", body);

Try / catch

try { await client.PostAsync("organizations/connections", body); }
catch (ApiException ex) when (ex.Message.Contains("already has a connection")) {
    // fetch and switch to PUT update flow
}

Prevention

When it happens

Trigger: A second POST /organizations/connections for an organization that already has a persisted connection of identical Type (e.g., a CloudBillingSync connection already exists and the client posts another; a duplicate Scim POST after the first succeeded). HasConnectionTypeAsync queries GetByOrganizationIdTypeAsync and returns true if any match exists.

Common situations: A retry-happy client re-submitting after a network timeout where the first POST actually succeeded (idempotency not implemented); two admins configuring the same connection type concurrently; a UI that does not check existing state before offering 'Create'; stale local state making the client believe no connection exists.

Related errors


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