{"record":{"id":"386cdd1258ee81db","repo":"bitwarden/server","slug":"you-can-only-archive-up-to-500-items-at-a-time","errorCode":null,"errorMessage":"You can only archive up to 500 items at a time.","messagePattern":"You can only archive up to 500 items at a time\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"src/Api/Vault/Controllers/CiphersController.cs","lineNumber":904,"sourceCode":"        var userId = _userService.GetProperUserId(User).Value;\n\n        var archivedCipherOrganizationDetails = await _archiveCiphersCommand.ArchiveManyAsync([id], userId);\n\n        if (archivedCipherOrganizationDetails.Count == 0)\n        {\n            throw new BadRequestException(\"Cipher was not archived. Ensure the provided ID is correct and you have permission to archive it.\");\n        }\n\n        var archivedCipher = archivedCipherOrganizationDetails.First();\n        return new CipherResponseModel(archivedCipher, await _userService.GetUserByPrincipalAsync(User), await GetOrganizationAbilityAsync(archivedCipher), _globalSettings);\n    }\n\n    [HttpPut(\"archive\")]\n    public async Task<ListResponseModel<CipherResponseModel>> PutArchiveMany([FromBody] CipherBulkArchiveRequestModel model)\n    {\n        if (!_globalSettings.SelfHosted && model.Ids.Count() > 500)\n        {\n            throw new BadRequestException(\"You can only archive up to 500 items at a time.\");\n        }\n\n        var userId = _userService.GetProperUserId(User).Value;\n        var user = await _userService.GetUserByPrincipalAsync(User);\n\n        var cipherIdsToArchive = new HashSet<Guid>(model.Ids);\n\n        var archivedCiphers = await _archiveCiphersCommand.ArchiveManyAsync(cipherIdsToArchive, userId);\n\n        if (archivedCiphers.Count == 0)\n        {\n            throw new BadRequestException(\"No ciphers were archived. Ensure the provided IDs are correct and you have permission to archive them.\");\n        }\n\n        var organizationAbilities = await GetOrganizationAbilitiesAsync(archivedCiphers);\n        var responses = archivedCiphers.Select(cipher =>\n            new CipherResponseModel(cipher, user, GetOrganizationAbility(cipher, organizationAbilities), _globalSettings)).ToArray();\n","sourceCodeStart":886,"sourceCodeEnd":922,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Vault/Controllers/CiphersController.cs#L886-L922","documentation":"PUT /ciphers/archive (PutArchiveMany, bulk) rejects requests with more than 500 ids when the deployment is NOT self-hosted (cloud only). The cap protects cloud throughput; self-hosted instances bypass it. Exceeding it returns HTTP 400.","triggerScenarios":"A bulk PUT /ciphers/archive whose `Ids` collection contains more than 500 entries on a cloud (non-self-hosted) deployment.","commonSituations":"A 'select all + archive' UI action over a large vault; a migration script archiving many items in one call; a client not chunking bulk operations.","solutions":["Chunk the id list into batches of <= 500 and issue multiple requests.","Surface the 500-item limit in the UI before the user triggers a bulk archive.","If operating self-hosted, note the cap does not apply there."],"exampleFix":"// before\nPUT /ciphers/archive  body: { \"ids\": [/* 750 ids */] }\n// after\nPUT /ciphers/archive  body: { \"ids\": first500 }\nPUT /ciphers/archive  body: { \"ids\": remaining250 }","handlingStrategy":"validation","validationCode":"const ARCHIVE_LIMIT = 500;\nasync function bulkArchive(ids) {\n  for (const chunk of chunkBy(ids, ARCHIVE_LIMIT)) {\n    await api.put('/ciphers/archive', { ids: chunk });\n  }\n}\nfunction chunkBy(arr, n) { const out = []; for (let i = 0; i < arr.length; i += n) out.push(arr.slice(i, i + n)); return out; }","typeGuard":"function isWithinBulkLimit(ids: unknown[], limit = 500): boolean {\n  return Array.isArray(ids) && ids.length <= limit;\n}","tryCatchPattern":null,"preventionTips":["Always chunk bulk operations into <= 500-id batches on cloud.","Show the limit in the UI before a 'select all' bulk action.","Remember self-hosted deployments are exempt from the cap."],"tags":["cipher","archive","bulk","limit","cloud","bad-request"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}