bitwarden/server · error · BadRequestException
Organization mismatch. Re-sync if you recently moved this it
Error message
Organization mismatch. Re-sync if you recently moved this item, then try again.
What it means
PUT /ciphers/{id} (Put), after the EncryptedFor check, compares the stored `cipher.OrganizationId` against the `OrganizationId` in the request body. A mismatch means the client's view is stale — the item was shared into/out of an org — and continuing would write ciphertext under the wrong key scope, so the server returns HTTP 400.
Source
Thrown at src/Api/Vault/Controllers/CiphersController.cs:270
// Validate the model was encrypted for the posting user
if (model.EncryptedFor != null)
{
if (model.EncryptedFor != user.Id)
{
_logger.LogError("Cipher was not encrypted for the current user. CipherId: {CipherId}, CurrentUser: {CurrentUserId}, EncryptedFor: {EncryptedFor}", id, user.Id, model.EncryptedFor);
throw new BadRequestException("Cipher was not encrypted for the current user. Please try again.");
}
}
ValidateClientVersionForFido2CredentialSupport(cipher);
var collectionIds = (await _collectionCipherRepository.GetManyByUserIdCipherIdAsync(user.Id, id)).Select(c => c.CollectionId).ToList();
var modelOrgId = string.IsNullOrWhiteSpace(model.OrganizationId) ?
(Guid?)null : new Guid(model.OrganizationId);
if (cipher.OrganizationId != modelOrgId)
{
throw new BadRequestException("Organization mismatch. Re-sync if you recently moved this item, " +
"then try again.");
}
await _cipherService.SaveDetailsAsync(model.ToCipherDetails(cipher), user.Id, model.LastKnownRevisionDate, collectionIds);
var response = new CipherResponseModel(cipher, user, await GetOrganizationAbilityAsync(cipher), _globalSettings);
return response;
}
[HttpPost("{id}")]
[Obsolete("This endpoint is deprecated. Use PUT method instead.")]
public async Task<CipherResponseModel> PostPut(Guid id, [FromBody] CipherRequestModel model)
{
return await Put(id, model);
}
[HttpPut("{id}/admin")]
public async Task<CipherMiniResponseModel> PutAdmin(Guid id, [FromBody] CipherRequestModel model)View on GitHub (pinned to e93b962371)
Solutions
- Sync the vault (GET /sync or GET /ciphers) and retry the edit with the current OrganizationId.
- To move the item between scopes, use the share endpoint rather than a plain PUT.
- Before saving, confirm the OrganizationId in the payload equals the server's current value.
Example fix
// before: client thinks the cipher is still personal
PUT /ciphers/{id} body: { "organizationId": null, ... }
// after: sync, then post the real org id
PUT /ciphers/{id} body: { "organizationId": "<orgGuid>", ... } Defensive patterns
Strategy: validation
Validate before calling
async function safePutCipher(id, payload) {
const current = await api.get(`/ciphers/${id}`);
if (payload.organizationId !== (current.organizationId ?? null)) {
throw new Error('OrganizationId mismatch; sync before editing, or use the share endpoint to move.');
}
return api.put(`/ciphers/${id}`, payload);
} Type guard
function orgIdMatches(payloadOrgId: string | null | undefined, serverOrgId: string | null): boolean {
const p = payloadOrgId && payloadOrgId.trim() ? payloadOrgId : null;
const s = serverOrgId ?? null;
return p === s;
} Try / catch
try { await api.put(`/ciphers/${id}`, payload); }
catch (e) {
if (e?.response?.status === 400 && /Organization mismatch/i.test(e.response.data?.message ?? '')) {
await syncVault(); // refresh OrganizationId, then retry once
} else throw e;
} Prevention
- Sync the vault after any share/move before editing the affected cipher.
- Use the share endpoint to change scope, not a plain PUT.
- Refresh the local cipher's OrganizationId before constructing the edit payload.
When it happens
Trigger: PUT /ciphers/{id} where the cipher was recently shared to an org (or removed from one) and the client posts the old OrganizationId (or null).
Common situations: The client was offline during a share/move; a race between two clients editing the same item; an org migration in progress; the client hasn't re-synced since the share.
Related errors
- Cipher was not encrypted for the current user. Please try ag
- Organization already belongs to a provider.
- You cannot delete accounts owned by an organization. Contact
- Invalid Billing Sync Key
- All existing reset password keys must be included in the rot
AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13).
Data as JSON: /api/errors/1ad11804d0236f02.
Report an issue: GitHub.