bitwarden/server · error · BadRequestException
All existing sends must be included in the rotation.
Error message
All existing sends must be included in the rotation.
What it means
Thrown by SendRotationValidator during key rotation. It loads every Bitwarden Send the user owns (each Send's name and data are encrypted with the user key) and requires the rotation request to include each one matched by Id. A missing Send would stay encrypted under the old key and become inaccessible, so the rotation is rejected.
Source
Thrown at src/Api/KeyManagement/Validators/SendRotationValidator.cs:44
_sendRepository = sendRepository;
}
public async Task<IReadOnlyList<Send>> ValidateAsync(User user, IEnumerable<SendWithIdRequestModel> sends)
{
var result = new List<Send>();
var existingSends = await _sendRepository.GetManyByUserIdAsync(user.Id);
if (existingSends == null || existingSends.Count == 0)
{
return result;
}
foreach (var existing in existingSends)
{
var send = sends.FirstOrDefault(c => c.Id == existing.Id);
if (send == null)
{
throw new BadRequestException("All existing sends must be included in the rotation.");
}
result.Add(send.UpdateSend(existing, _sendAuthorizationService));
}
return result;
}
}
View on GitHub (pinned to e93b962371)
Solutions
- Sync the vault/Sends so the client knows about all Sends immediately before building the rotation request.
- Include every Send Id the user has, re-encrypted with the new key.
- Delete any unwanted Sends before rotating rather than omitting them.
- Validate the submitted Send Id set is a superset of the server set before sending.
Example fix
// before const sends = localSends.map(s => reencryptSend(s)); // after await syncSends(); const sends = allSends.map(s => reencryptSend(s));
Defensive patterns
Strategy: validation
Validate before calling
const sends = await api.getSends();
const submitted = new Set(payload.sends.map(s => s.id));
const missing = sends.filter(s => !submitted.has(s.id));
if (missing.length) {
throw new Error(`Rotation is missing sends: ${missing.map(s => s.id).join(', ')}`);
} Type guard
function isCompleteSendRotation(existing: { id: string }[], submitted: { id: string }[]): boolean {
const have = new Set(submitted.map(s => s.id));
return existing.every(s => have.has(s.id));
} Try / catch
try {
await api.rotateKey(payload);
} catch (e) {
if (e.status === 400 && /sends must be included/i.test(e.message)) {
await syncSends();
payload.sends = allSends.map(s => reencryptSend(s));
return api.rotateKey(payload);
}
throw e;
} Prevention
- Sync Sends immediately before constructing the rotation payload.
- Delete unwanted Sends before rotating rather than omitting them.
- Assert the submitted Send ids cover every server Send.
When it happens
Trigger: Key-rotation request whose sends array omits a Send.Id that exists for the user. A Send was created in another session after the client cached the list; the client sent a partial list; an Id was malformed.
Common situations: User created a Send on another device and then rotated keys here; client enumerated sends from local state that was stale; a sync race during rotation.
Related errors
- All existing trusted devices must be included in the rotatio
- All existing emergency access keys must be included in the r
- All existing folders must be included in the rotation.
- All existing reset password keys must be included in the rot
- All existing webauthn prf keys must be included in the rotat
AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13).
Data as JSON: /api/errors/19e46102d1a53649.
Report an issue: GitHub.