bitwarden/server · error · BadRequestException

Only the owner of an organization can remove sponsorship.

Error message

Only the owner of an organization can remove sponsorship.

What it means

Thrown (HTTP 400) on DELETE /sponsored/{sponsoredOrgId} when _currentContext.OrganizationOwner(sponsoredOrgId) returns false. Only an Owner of the sponsored organization may remove its sponsorship.

Source

Thrown at src/Api/Billing/Controllers/OrganizationSponsorshipsController.cs:280

    {
        var sponsorships = await _organizationSponsorshipRepository.GetManyBySponsoringOrganizationAsync(sponsoringOrgId);
        var existingOrgSponsorship = sponsorships.FirstOrDefault(s => s.FriendlyName != null && s.FriendlyName.Equals(sponsoredFriendlyName, StringComparison.OrdinalIgnoreCase));
        if (existingOrgSponsorship == null)
        {
            throw new BadRequestException("The specified sponsored organization could not be found under the given sponsoring organization.");
        }
        await _revokeSponsorshipCommand.RevokeSponsorshipAsync(existingOrgSponsorship);
    }

    [Authorize("Application")]
    [HttpDelete("sponsored/{sponsoredOrgId}")]
    [SelfHosted(NotSelfHostedOnly = true)]
    public async Task RemoveSponsorship(Guid sponsoredOrgId)
    {

        if (!await _currentContext.OrganizationOwner(sponsoredOrgId))
        {
            throw new BadRequestException("Only the owner of an organization can remove sponsorship.");
        }

        var existingOrgSponsorship = await _organizationSponsorshipRepository
            .GetBySponsoredOrganizationIdAsync(sponsoredOrgId);

        await _removeSponsorshipCommand.RemoveSponsorshipAsync(existingOrgSponsorship);
    }

    [Authorize("Application")]
    [HttpPost("sponsored/{sponsoredOrgId}/remove")]
    [Obsolete("This endpoint is deprecated. Use DELETE /sponsored/{sponsoredOrgId} instead.")]
    [SelfHosted(NotSelfHostedOnly = true)]
    public async Task PostRemoveSponsorship(Guid sponsoredOrgId)
    {
        await RemoveSponsorship(sponsoredOrgId);
    }

    [HttpGet("{sponsoringOrgId}/sync-status")]

View on GitHub (pinned to e93b962371)

Solutions

  1. Have an Owner of the sponsored organization perform the removal.
  2. Elevate the intended user to the Owner role, then retry.
  3. Confirm the sponsoredOrgId corresponds to an org the user owns.
Defensive patterns

Strategy: validation

Validate before calling

// Confirm ownership before offering removal.
const isOwner = await isOrgOwner(sponsoredOrgId);
if (!isOwner) throw new Error('Only an Owner of the sponsored org can remove sponsorship');

Try / catch

try {
  await del(`/organization-sponsorships/sponsored/${sponsoredOrgId}`);
} catch (e) {
  if (e.isBadRequest && /owner of an organization/i.test(e.message)) {
    prompt('Ask an Owner of this organization to remove the sponsorship.');
  } else { throw e; }
}

Prevention

When it happens

Trigger: A non-owner user (Admin, custom role, member) attempts sponsorship removal; the user is an owner of a different org.

Common situations: Admin vs Owner role confusion; user belongs to several orgs and targets the wrong one.

Related errors


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