{"record":{"id":"4a2d1346779f3dca","repo":"bitwarden/server","slug":"requested-collections-must-belong-to-the-same-orga","errorCode":null,"errorMessage":"Requested collections must belong to the same organization.","messagePattern":"Requested collections must belong to the same organization\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Api/AdminConsole/Authorization/Collections/BulkCollectionAuthorizationHandler.cs","lineNumber":65,"sourceCode":"        if (resources == null || !resources.Any())\n        {\n            context.Fail();\n            return;\n        }\n\n        // Acting user is not authenticated, fail\n        if (!_currentContext.UserId.HasValue)\n        {\n            context.Fail();\n            return;\n        }\n\n        _targetOrganizationId = resources.First().OrganizationId;\n\n        // Ensure all target collections belong to the same organization\n        if (resources.Any(tc => tc.OrganizationId != _targetOrganizationId))\n        {\n            throw new BadRequestException(\"Requested collections must belong to the same organization.\");\n        }\n\n        var org = _currentContext.GetOrganization(_targetOrganizationId);\n\n        var authorized = false;\n\n        switch (requirement)\n        {\n            case not null when requirement == BulkCollectionOperations.Create:\n                authorized = await CanCreateAsync(org);\n                break;\n\n            case not null when requirement == BulkCollectionOperations.Read:\n            case not null when requirement == BulkCollectionOperations.ReadAccess:\n                authorized = await CanReadAsync(resources, org);\n                break;\n\n            case not null when requirement == BulkCollectionOperations.ReadWithAccess:","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/AdminConsole/Authorization/Collections/BulkCollectionAuthorizationHandler.cs#L47-L83","documentation":"A BadRequestException (HTTP 400) thrown by BulkCollectionAuthorizationHandler when a bulk collection operation targets collections that do not all belong to the same organization. The handler takes the first collection's OrganizationId as the target and rejects the request if any collection in the batch has a different OrganizationId. This enforces single-org scope for bulk collection authorization.","triggerScenarios":"A bulk collection API call (create, read, update, delete, access modification) includes collection IDs from two or more different organizations in a single request. The handler detects the mismatch before evaluating per-collection permissions.","commonSituations":"A client bug concatenates collection IDs from multiple org contexts into one bulk request. A user has collections from multiple orgs in their vault and a bulk-select UI inadvertently mixes them. API misuse by a script or integration that doesn't scope by org.","solutions":["Ensure all collection IDs in a single bulk request belong to the same organization.","On the client, partition collection IDs by OrganizationId and issue separate bulk requests per org.","Validate the collection list client-side before sending: group by org and assert a single group.","If building a bulk API client, add a pre-flight check that loads collection org IDs and splits the batch."],"exampleFix":"// before: mixing collections from different orgs\nvar allCollectionIds = orgACollections.Concat(orgBCollections).ToList();\nawait api.BulkUpdateCollectionsAsync(allCollectionIds, ...);\n// after: split by organization\nawait api.BulkUpdateCollectionsAsync(orgACollections, ...);\nawait api.BulkUpdateCollectionsAsync(orgBCollections, ...);","handlingStrategy":"validation","validationCode":"// Group collections by org before issuing a bulk request\nvar grouped = collections.GroupBy(c => c.OrganizationId);\nif (grouped.Count() > 1)\n    throw new InvalidOperationException(\"Cannot bulk-operate on collections from multiple organizations.\");\nforeach (var group in grouped)\n    await api.BulkCollectionOpAsync(group.Select(c => c.Id).ToList());","typeGuard":"static bool AllSameOrg(IEnumerable<Collection> collections)\n    => collections.Select(c => c.OrganizationId).Distinct().Count() <= 1;","tryCatchPattern":"try { await api.BulkUpdateCollectionsAsync(collectionIds, ...); }\ncatch (BadRequestException ex) when (ex.Message.Contains(\"same organization\"))\n{ /* Split the batch by org and retry each group separately */ }","preventionTips":["In bulk-select UIs, prevent selecting collections across org boundaries.","Build a client-side helper that partitions collection IDs by OrganizationId before any bulk call.","Add an integration test that sends a mixed-org batch and asserts a 400 response."],"tags":["api","collections","authorization","bulk-operations","validation","http-400"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}