{"record":{"id":"1ad11804d0236f02","repo":"bitwarden/server","slug":"organization-mismatch-re-sync-if-you-recently-mov","errorCode":null,"errorMessage":"Organization mismatch. Re-sync if you recently moved this item, then try again.","messagePattern":"Organization mismatch\\. Re-sync if you recently moved this item, then try again\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Api/Vault/Controllers/CiphersController.cs","lineNumber":270,"sourceCode":"\n        // Validate the model was encrypted for the posting user\n        if (model.EncryptedFor != null)\n        {\n            if (model.EncryptedFor != user.Id)\n            {\n                _logger.LogError(\"Cipher was not encrypted for the current user. CipherId: {CipherId}, CurrentUser: {CurrentUserId}, EncryptedFor: {EncryptedFor}\", id, user.Id, model.EncryptedFor);\n                throw new BadRequestException(\"Cipher was not encrypted for the current user. Please try again.\");\n            }\n        }\n\n        ValidateClientVersionForFido2CredentialSupport(cipher);\n\n        var collectionIds = (await _collectionCipherRepository.GetManyByUserIdCipherIdAsync(user.Id, id)).Select(c => c.CollectionId).ToList();\n        var modelOrgId = string.IsNullOrWhiteSpace(model.OrganizationId) ?\n            (Guid?)null : new Guid(model.OrganizationId);\n        if (cipher.OrganizationId != modelOrgId)\n        {\n            throw new BadRequestException(\"Organization mismatch. Re-sync if you recently moved this item, \" +\n                \"then try again.\");\n        }\n\n        await _cipherService.SaveDetailsAsync(model.ToCipherDetails(cipher), user.Id, model.LastKnownRevisionDate, collectionIds);\n\n        var response = new CipherResponseModel(cipher, user, await GetOrganizationAbilityAsync(cipher), _globalSettings);\n        return response;\n    }\n\n    [HttpPost(\"{id}\")]\n    [Obsolete(\"This endpoint is deprecated. Use PUT method instead.\")]\n    public async Task<CipherResponseModel> PostPut(Guid id, [FromBody] CipherRequestModel model)\n    {\n        return await Put(id, model);\n    }\n\n    [HttpPut(\"{id}/admin\")]\n    public async Task<CipherMiniResponseModel> PutAdmin(Guid id, [FromBody] CipherRequestModel model)","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Vault/Controllers/CiphersController.cs#L252-L288","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before: client thinks the cipher is still personal\nPUT /ciphers/{id}  body: { \"organizationId\": null, ... }\n// after: sync, then post the real org id\nPUT /ciphers/{id}  body: { \"organizationId\": \"<orgGuid>\", ... }","handlingStrategy":"validation","validationCode":"async function safePutCipher(id, payload) {\n  const current = await api.get(`/ciphers/${id}`);\n  if (payload.organizationId !== (current.organizationId ?? null)) {\n    throw new Error('OrganizationId mismatch; sync before editing, or use the share endpoint to move.');\n  }\n  return api.put(`/ciphers/${id}`, payload);\n}","typeGuard":"function orgIdMatches(payloadOrgId: string | null | undefined, serverOrgId: string | null): boolean {\n  const p = payloadOrgId && payloadOrgId.trim() ? payloadOrgId : null;\n  const s = serverOrgId ?? null;\n  return p === s;\n}","tryCatchPattern":"try { await api.put(`/ciphers/${id}`, payload); }\ncatch (e) {\n  if (e?.response?.status === 400 && /Organization mismatch/i.test(e.response.data?.message ?? '')) {\n    await syncVault(); // refresh OrganizationId, then retry once\n  } else throw e;\n}","preventionTips":["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."],"tags":["cipher","organization","sync","vault","bad-request"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}