{"record":{"id":"c01bdc9f236a61c3","repo":"bitwarden/server","slug":"the-model-state-is-invalid","errorCode":null,"errorMessage":"The model state is invalid.","messagePattern":"The model state is invalid\\.","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Api/Auth/Controllers/AccountsController.cs","lineNumber":371,"sourceCode":"        var user = await _userService.GetUserByPrincipalAsync(User);\n        if (user == null)\n        {\n            throw new UnauthorizedAccessException();\n        }\n\n        var result = await _changeKdfCommand.ChangeKdfAsync(user, model.MasterPasswordHash, model.AuthenticationData.ToData(), model.UnlockData.ToData());\n        if (result.Succeeded)\n        {\n            return;\n        }\n\n        foreach (var error in result.Errors)\n        {\n            ModelState.AddModelError(string.Empty, error.Description);\n        }\n\n        await Task.Delay(2000);\n        throw new BadRequestException(ModelState);\n    }\n\n    [HttpPost(\"security-stamp\")]\n    public async Task PostSecurityStamp([FromBody] SecretVerificationRequestModel model)\n    {\n        var user = await _userService.GetUserByPrincipalAsync(User);\n        if (user == null)\n        {\n            throw new UnauthorizedAccessException();\n        }\n\n        var result = await _userService.RefreshSecurityStampAsync(user, model.Secret);\n        if (result.Succeeded)\n        {\n            return;\n        }\n\n        foreach (var error in result.Errors)","sourceCodeStart":353,"sourceCodeEnd":389,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Auth/Controllers/AccountsController.cs#L353-L389","documentation":"In POST /accounts/kdf, when _changeKdfCommand.ChangeKdfAsync returns a failed result, each IdentityError is added to ModelState, a 2-second delay is applied, and BadRequestException(ModelState) is thrown → HTTP 400. The change-KDF command validates the master password and the re-encrypted authentication/unlock data; any failure surfaces here.","triggerScenarios":"Wrong master password hash supplied with the KDF change; AuthenticationData or UnlockData that fail to decrypt/re-encrypt under the new KDF; invalid target KDF parameters (e.g. Argon2id with out-of-range memory/parallelism).","commonSituations":"User mistyped the master password during KDF migration; client built the re-encrypted payload with stale vault keys; Argon2id memory/iterations below server minimums; vault has ciphers the client failed to include in the re-encryption payload.","solutions":["Inspect ValidationErrors for the specific failure (password vs. re-encryption vs. parameter range).","Re-derive MasterPasswordHash from the correct, current master password and KDF settings.","Rebuild AuthenticationData/UnlockData by re-encrypting the user key with the NEW KDF-derived key on a fresh, complete vault sync.","Validate the requested KDF parameters against the server's allowed ranges before submitting."],"exampleFix":"// before\nmodel.AuthenticationData = ReencryptWith(oldKdf);\n// after\nmodel.MasterPasswordHash = DeriveHash(password, newKdf);\nmodel.AuthenticationData = ReencryptUserKey(userKey, password, newKdf);\nmodel.UnlockData = ReencryptWith(newKdf);","handlingStrategy":"validation","validationCode":"// Validate KDF target params and re-encrypt with a complete vault before posting\nif (!KdfParamsValid(newKdf)) errors.Add(\"KDF params out of range\");\nif (!vaultFullySynced) errors.Add(\"Sync vault before KDF change\");","typeGuard":null,"tryCatchPattern":"try { await client.PostKdfAsync(model); }\ncatch (BadRequestException ex) { /* read ex.ModelState: password vs re-encryption vs params */ }","preventionTips":["Re-encrypt the entire vault with the new KDF before submitting.","Validate Argon2id memory/parallelism against server minimums.","Derive MasterPasswordHash from the correct current password."],"tags":["validation","bad-request","kdf","master-password","encryption","model-state"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}