{"record":{"id":"e39a8d45af9019d7","repo":"bitwarden/server","slug":"you-can-only-unarchive-up-to-500-items-at-a-time","errorCode":null,"errorMessage":"You can only unarchive up to 500 items at a time.","messagePattern":"You can only unarchive up to 500 items at a time\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"src/Api/Vault/Controllers/CiphersController.cs","lineNumber":1108,"sourceCode":"        if (unarchivedCipherDetails.Count == 0)\n        {\n            throw new BadRequestException(\"Cipher was not unarchived. Ensure the provided ID is correct and you have permission to archive it.\");\n        }\n\n        var unarchivedCipher = unarchivedCipherDetails.First();\n        return new CipherResponseModel(unarchivedCipher,\n            await _userService.GetUserByPrincipalAsync(User),\n            await GetOrganizationAbilityAsync(unarchivedCipher),\n            _globalSettings\n        );\n    }\n\n    [HttpPut(\"unarchive\")]\n    public async Task<ListResponseModel<CipherResponseModel>> PutUnarchiveMany([FromBody] CipherBulkUnarchiveRequestModel model)\n    {\n        if (!_globalSettings.SelfHosted && model.Ids.Count() > 500)\n        {\n            throw new BadRequestException(\"You can only unarchive 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 cipherIdsToUnarchive = new HashSet<Guid>(model.Ids);\n\n        var unarchivedCipherOrganizationDetails = await _unarchiveCiphersCommand.UnarchiveManyAsync(cipherIdsToUnarchive, userId);\n\n        if (unarchivedCipherOrganizationDetails.Count == 0)\n        {\n            throw new BadRequestException(\"Ciphers were not unarchived. Ensure the provided ID is correct and you have permission to archive it.\");\n        }\n\n        var organizationAbilities = await GetOrganizationAbilitiesAsync(unarchivedCipherOrganizationDetails);\n        var responses = unarchivedCipherOrganizationDetails.Select(cipher =>\n            new CipherResponseModel(cipher, user, GetOrganizationAbility(cipher, organizationAbilities), _globalSettings)).ToArray();\n","sourceCodeStart":1090,"sourceCodeEnd":1126,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Vault/Controllers/CiphersController.cs#L1090-L1126","documentation":"PUT /ciphers/unarchive (PutUnarchiveMany, bulk) rejects more than 500 ids on non-self-hosted (cloud) deployments and returns HTTP 400. The cap mirrors the other bulk operations; self-hosted bypasses it.","triggerScenarios":"A bulk PUT /ciphers/unarchive whose `Ids` contains more than 500 entries on a cloud deployment.","commonSituations":"A 'select all + unarchive' UI over a large vault; a restore script not chunking requests; bulk restore after a mass archive.","solutions":["Chunk the id list into batches of <= 500 and issue multiple PUT /ciphers/unarchive calls.","Surface the 500-item limit in the UI before triggering bulk unarchive.","Note the cap is cloud-only; self-hosted is unaffected."],"exampleFix":"// before\nPUT /ciphers/unarchive  body: { \"ids\": [/* 650 ids */] }\n// after\nPUT /ciphers/unarchive  body: { \"ids\": first500 }\nPUT /ciphers/unarchive  body: { \"ids\": remaining150 }","handlingStrategy":"validation","validationCode":"const UNARCHIVE_LIMIT = 500;\nasync function bulkUnarchive(ids) {\n  for (const chunk of chunkBy(ids, UNARCHIVE_LIMIT)) {\n    await api.put('/ciphers/unarchive', { ids: chunk });\n  }\n}","typeGuard":"function isWithinBulkLimit(ids: unknown[], limit = 500): boolean {\n  return Array.isArray(ids) && ids.length <= limit;\n}","tryCatchPattern":null,"preventionTips":["Chunk bulk unarchive to <= 500 ids on cloud.","Surface the limit in the UI before mass unarchive.","Remember self-hosted deployments are exempt."],"tags":["cipher","unarchive","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"}