{"record":{"id":"07772f52695a3989","repo":"bitwarden/server","slug":"keyconnectorkeywrappeduserkey-and-accountkeys-must","errorCode":null,"errorMessage":"KeyConnectorKeyWrappedUserKey and AccountKeys must be supplied.","messagePattern":"KeyConnectorKeyWrappedUserKey and AccountKeys must be supplied\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Api/KeyManagement/Models/Requests/SetKeyConnectorKeyRequestModel.cs","lineNumber":110,"sourceCode":"\n    // TODO removed with https://bitwarden.atlassian.net/browse/PM-27328\n    public User ToUser(User existingUser)\n    {\n        existingUser.Kdf = Kdf!.Value;\n        existingUser.KdfIterations = KdfIterations!.Value;\n        existingUser.KdfMemory = KdfMemory;\n        existingUser.KdfParallelism = KdfParallelism;\n        existingUser.Key = Key;\n        Keys!.ToUser(existingUser);\n        return existingUser;\n    }\n\n    public KeyConnectorKeysData ToKeyConnectorKeysData()\n    {\n        // TODO remove validation with https://bitwarden.atlassian.net/browse/PM-27328\n        if (string.IsNullOrEmpty(KeyConnectorKeyWrappedUserKey) || AccountKeys == null)\n        {\n            throw new BadRequestException(\"KeyConnectorKeyWrappedUserKey and AccountKeys must be supplied.\");\n        }\n\n        return new KeyConnectorKeysData\n        {\n            KeyConnectorKeyWrappedUserKey = KeyConnectorKeyWrappedUserKey,\n            AccountKeys = AccountKeys,\n            OrgIdentifier = OrgIdentifier,\n            ContainedKeyId = KeyId.FromHexEncodedString(ContainedKeyId)\n        };\n    }\n}\n","sourceCodeStart":92,"sourceCodeEnd":122,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/KeyManagement/Models/Requests/SetKeyConnectorKeyRequestModel.cs#L92-L122","documentation":"Thrown by SetKeyConnectorKeyRequestModel.ToKeyConnectorKeysData() when either KeyConnectorKeyWrappedUserKey is null/empty or AccountKeys is null. This is a transitional validation (marked with a TODO referencing PM-27328 for removal) ensuring both fields are present when migrating or setting up Key Connector keys. BadRequestException returns HTTP 400.","triggerScenarios":"POST/PUT to the key-connector key-setting endpoint (e.g., /users/key-connector) with a partial payload — KeyConnectorKeyWrappedUserKey present but AccountKeys missing, or vice versa. The IsV2Request() helper checks the same condition; this throw fires when ToKeyConnectorKeysData() is called on a non-V2 request.","commonSituations":"Client sends a V1-style request (only Key/Keys fields) to an endpoint that internally calls ToKeyConnectorKeysData(); key connector migration step skipped or partially completed; client library version mismatch where one field was added but not the other; org rolling out Key Connector with an outdated client.","solutions":["Ensure both KeyConnectorKeyWrappedUserKey and AccountKeys are populated in the request body.","Use IsV2Request() to check before calling ToKeyConnectorKeysData() and handle V1 requests separately.","Update the calling client to the latest version that sends both fields.","Verify the Key Connector configuration flow is complete — the wrapped key and account keys are generated together during enrollment."],"exampleFix":"// before\nvar data = request.ToKeyConnectorKeysData(); // throws if incomplete\n\n// after — check V2 readiness first\nif (!request.IsV2Request())\n{\n    // handle V1 path or return a clear error\n    return BadRequest(\"This endpoint requires KeyConnectorKeyWrappedUserKey and AccountKeys.\");\n}\nvar data = request.ToKeyConnectorKeysData();","handlingStrategy":"validation","validationCode":"// Validate request completeness before calling ToKeyConnectorKeysData\nif (string.IsNullOrEmpty(request.KeyConnectorKeyWrappedUserKey) || request.AccountKeys == null)\n    return BadRequest(\"Both KeyConnectorKeyWrappedUserKey and AccountKeys must be supplied.\");\nvar data = request.ToKeyConnectorKeysData();","typeGuard":"public static bool IsCompleteKeyConnectorRequest(SetKeyConnectorKeyRequestModel req) =>\n    req.IsV2Request(); // returns true only when both fields are present","tryCatchPattern":"try\n{\n    var data = request.ToKeyConnectorKeysData();\n}\ncatch (BadRequestException ex) when (ex.Message.Contains(\"KeyConnectorKeyWrappedUserKey\"))\n{\n    return BadRequest(\"Key Connector setup requires both wrapped key and account keys. \" +\n        \"Ensure the client is running a version that supports Key Connector V2.\");\n}","preventionTips":["Call IsV2Request() before ToKeyConnectorKeysData() to branch V1 and V2 handling.","Update client libraries to the latest version that sends both fields together.","Complete the Key Connector enrollment flow in full — partial payloads are rejected."],"tags":["key-management","key-connector","validation","migration","csharp","aspnet"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}