{"record":{"id":"c9860c92122153eb","repo":"bitwarden/server","slug":"you-can-only-delete-up-to-500-folders-at-a-time","errorCode":null,"errorMessage":"You can only delete up to 500 folders at a time.","messagePattern":"You can only delete up to 500 folders at a time\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"src/Api/Vault/Controllers/FoldersController.cs","lineNumber":122,"sourceCode":"        }\n\n        await _cipherService.DeleteFolderAsync(folder);\n    }\n\n    [HttpPost(\"{id}/delete\")]\n    [Obsolete(\"This endpoint is deprecated. Use DELETE method instead.\")]\n    public async Task PostDelete(string id)\n    {\n        await Delete(id);\n    }\n\n    [HttpDelete(\"\")]\n    [RequireFeature(FeatureFlagKeys.VFO1Foundation)]\n    public async Task DeleteMany([FromBody] FolderBulkDeleteRequestModel model)\n    {\n        if (!_globalSettings.SelfHosted && model.Ids.Count() > 500)\n        {\n            throw new BadRequestException(\"You can only delete up to 500 folders at a time.\");\n        }\n\n        var userId = _userService.GetProperUserId(User).Value;\n        await _deleteManyFoldersCommand.DeleteManyAsync(model.Ids, userId);\n    }\n\n    [HttpDelete(\"all\")]\n    public async Task DeleteAll()\n    {\n        var userId = _userService.GetProperUserId(User).Value;\n        var allFolders = await _folderRepository.GetManyByUserIdAsync(userId);\n\n        foreach (var folder in allFolders)\n        {\n            await _cipherService.DeleteFolderAsync(folder);\n        }\n    }\n}","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Vault/Controllers/FoldersController.cs#L104-L140","documentation":"Thrown by FoldersController.DeleteMany (DELETE /folders) when model.Ids contains more than 500 IDs AND the instance is not self-hosted (_globalSettings.SelfHosted is false). The endpoint is gated behind the VFO1Foundation feature flag. Self-hosted instances have no such limit. The 500-item cap protects cloud database performance during bulk folder deletion.","triggerScenarios":"Sending a bulk delete request with more than 500 folder IDs on the Bitwarden cloud service; client batching logic that doesn't chunk requests; a script or migration attempting to delete all folders in a single call.","commonSituations":"Bulk cleanup scripts; client-side 'select all and delete' that sends all IDs at once; migration tooling that doesn't respect API limits.","solutions":["Batch the deletion into chunks of 500 or fewer IDs per request","Use the DELETE /folders/all endpoint if the intent is to delete every folder","On self-hosted, this limit is not enforced, but batching is still recommended for performance","Implement client-side chunking that splits large ID lists before calling the API"],"exampleFix":"// before (sends all at once, fails on cloud if > 500)\nawait api.DeleteManyFoldersAsync(allFolderIds);\n\n// after (chunked into batches of 500)\nconst batchSize = 500;\nfor (let i = 0; i < allFolderIds.length; i += batchSize) {\n    const batch = allFolderIds.slice(i, i + batchSize);\n    await api.DeleteManyFoldersAsync(batch);\n}","handlingStrategy":"validation","validationCode":"// Chunk folder IDs before calling bulk delete\nconst int MaxBatchSize = 500;\nforeach (var batch in allFolderIds.Chunk(MaxBatchSize))\n{\n    await api.DeleteManyFoldersAsync(batch.ToList());\n}\n// Or: use DELETE /folders/all if deleting everything","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always chunk bulk operations into batches of 500 or fewer IDs","Use the DELETE /folders/all endpoint when the intent is to delete every folder","On self-hosted, batching is optional but recommended for performance","Log the total count before sending to catch unexpectedly large batches early"],"tags":["folders","bulk-operations","batching","limit","cloud-only","feature-flag"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}