bitwarden/server · error · BadRequestException

All existing folders must be included in the rotation.

Error message

All existing folders must be included in the rotation.

What it means

Thrown by FolderRotationValidator during key rotation. It loads every folder the user owns and requires the rotation request to include each one matched by Id, because each folder's name is encrypted with the user key. A missing folder would remain under the old key and become unreadable, so the whole rotation is rejected.

Source

Thrown at src/Api/KeyManagement/Validators/FolderRotationValidator.cs:33

        _folderRepository = folderRepository;
    }

    public async Task<IEnumerable<Folder>> ValidateAsync(User user, IEnumerable<FolderWithIdRequestModel> folders)
    {
        var result = new List<Folder>();

        var existingFolders = await _folderRepository.GetManyByUserIdAsync(user.Id);
        if (existingFolders == null || existingFolders.Count == 0)
        {
            return result;
        }

        foreach (var existing in existingFolders)
        {
            var folder = folders.FirstOrDefault(c => c.Id == existing.Id);
            if (folder == null)
            {
                throw new BadRequestException("All existing folders must be included in the rotation.");
            }
            result.Add(folder.ToFolder(existing));
        }
        return result;
    }
}

View on GitHub (pinned to e93b962371)

Solutions

  1. Sync/refresh the vault so the client knows about all folders immediately before building the rotation request.
  2. Include every folder Id the user has, re-encrypted with the new key.
  3. Delete any unwanted folders before rotating rather than omitting them from the rotation list.
  4. Validate the submitted folder Id set is a superset of the server folder set before sending.

Example fix

// before
const folders = localVault.folders.map(f => ({ id: f.id, name: reencrypt(f.name) }));

// after
await vault.sync();
const folders = vault.folders.map(f => ({ id: f.id, name: reencrypt(f.name) }));
Defensive patterns

Strategy: validation

Validate before calling

const folders = await api.getFolders();
const submitted = new Set(payload.folders.map(f => f.id));
const missing = folders.filter(f => !submitted.has(f.id));
if (missing.length) {
  throw new Error(`Rotation is missing folders: ${missing.map(f => f.id).join(', ')}`);
}

Type guard

function isCompleteFolderRotation(existing: { id: string }[], submitted: { id: string }[]): boolean {
  const have = new Set(submitted.map(s => s.id));
  return existing.every(f => have.has(f.id));
}

Try / catch

try {
  await api.rotateKey(payload);
} catch (e) {
  if (e.status === 400 && /folders must be included/i.test(e.message)) {
    await vault.sync();
    payload.folders = vault.folders.map(f => ({ id: f.id, name: reencrypt(f.name) }));
    return api.rotateKey(payload);
  }
  throw e;
}

Prevention

When it happens

Trigger: Key-rotation request whose folders array omits a Folder.Id that exists for the user. A folder was created in another session after the client cached the folder list; the client sent a partial list; an Id was malformed.

Common situations: User created a folder on another device/client and then rotated keys here; client enumerated folders from local vault state that was out of sync; a sync race during rotation.

Related errors


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