bitwarden/server · error · NotFoundException

One or more collections not found.

Error message

One or more collections not found.

What it means

Thrown by POST /bulk-collection-access on CollectionsController when the number of collections returned by GetManyByManyIdsAsync that match the requested orgId differs from the count of ids submitted. Any id that does not exist or belongs to a different org causes the mismatch, yielding a 404 'One or more collections not found.' Unlike the no-message NotFoundException, this one carries an explicit message so the client can tell it is an input problem.

Source

Thrown at src/Api/AdminConsole/Controllers/CollectionsController.cs:234

        }

        return new CollectionAccessDetailsResponseModel(collectionWithPermissions);
    }

    [HttpPost("{id}")]
    [Obsolete("This endpoint is deprecated. Use PUT /{id} instead.")]
    public async Task<CollectionResponseModel> PostPut(Guid orgId, Guid id, [FromBody] UpdateCollectionRequestModel model)
    {
        return await Put(orgId, id, model);
    }

    [HttpPost("bulk-access")]
    public async Task PostBulkCollectionAccess(Guid orgId, [FromBody] BulkCollectionAccessRequestModel model)
    {
        var collections = await _collectionRepository.GetManyByManyIdsAsync(model.CollectionIds);
        if (collections.Count(c => c.OrganizationId == orgId) != model.CollectionIds.Count())
        {
            throw new NotFoundException("One or more collections not found.");
        }

        var result = await _authorizationService.AuthorizeAsync(User, collections,
            new[] { BulkCollectionOperations.ModifyUserAccess, BulkCollectionOperations.ModifyGroupAccess });

        if (!result.Succeeded)
        {
            throw new NotFoundException();
        }

        await _bulkAddCollectionAccessCommand.AddAccessAsync(
            collections,
            model.Users?.Select(u => u.ToSelectionReadOnly()).ToList(),
            model.Groups?.Select(g => g.ToSelectionReadOnly()).ToList());
    }

    [HttpDelete("{id}")]
    public async Task Delete(Guid orgId, Guid id)

View on GitHub (pinned to e93b962371)

Solutions

  1. Pre-filter the submitted ids against the live collection list for the org to drop unknown/duplicate ids.
  2. De-duplicate CollectionIds before submitting (the count comparison is order/count-sensitive).
  3. Refresh the source collection selection if any id is older than the last org list load.
  4. Scope the request to a single organization; never mix ids from multiple orgs.

Example fix

// before
model.CollectionIds = selectedIds;
await api.post(`/collections/bulk-access`, model);

// after
var live = new HashSet<Guid>((await collectionApi.List(orgId)).Select(c => c.Id));
model.CollectionIds = selectedIds.Where(i => live.Contains(i)).Distinct();
await api.post(`/collections/bulk-access`, model);
Defensive patterns

Strategy: validation

Validate before calling

// De-duplicate and intersect submitted ids with the live org collection list
var live = (await collectionApi.ListAsync(orgId)).Select(c => c.Id).ToHashSet();
model.CollectionIds = model.CollectionIds
    .Where(i => live.Contains(i))
    .Distinct()
    .ToArray();
if (!model.CollectionIds.Any()) return; // nothing valid to send

Type guard

static bool AllCollectionsExist(IEnumerable<Guid> submitted, HashSet<Guid> live)
    => submitted.Distinct().All(i => live.Contains(i));

Try / catch

try { await api.PostAsync("/collections/bulk-access", model); }
catch (ApiException e) when (e.StatusCode == HttpStatusCode.NotFound
    && e.Message.Contains("not found"))
{ await refreshCollections(); throw new RetryableValidationError(e); }

Prevention

When it happens

Trigger: Submitting a bulk-access request where at least one CollectionId is stale/deleted, belongs to another organization, or is malformed (and thus not returned). Duplicate ids in the request that resolve to one row can also skew the count.

Common situations: Bulk permission dialog left open while collections were deleted; cross-org copy of ids; client sending the same id twice; integration granting access across orgs with a flat id list.

Related errors


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