{"record":{"id":"f6bd5ae5341c27d1","repo":"bitwarden/server","slug":"please-provide-a-device-type","errorCode":null,"errorMessage":"Please provide a device type","messagePattern":"Please provide a device type","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Api/Controllers/DevicesController.cs","lineNumber":328,"sourceCode":"    [HttpPost(\"lost-trust\")]\n    public void PostLostTrust()\n    {\n        var userId = _currentContext.UserId.GetValueOrDefault();\n        if (userId == default)\n        {\n            throw new UnauthorizedAccessException();\n        }\n\n        var deviceId = _currentContext.DeviceIdentifier;\n        if (deviceId == null)\n        {\n            throw new BadRequestException(\"Please provide a device identifier\");\n        }\n\n        var deviceType = _currentContext.DeviceType;\n        if (deviceType == null)\n        {\n            throw new BadRequestException(\"Please provide a device type\");\n        }\n\n        _logger.LogError(\"User {id} has a device key, but didn't receive decryption keys for device {device} of type {deviceType}\", userId,\n            deviceId, deviceType);\n    }\n\n}\n","sourceCodeStart":310,"sourceCodeEnd":336,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Controllers/DevicesController.cs#L310-L336","documentation":"Thrown by POST /devices/lost-trust when the device identifier is present but the device type is null in the request context. The endpoint logs a trust-loss event that includes the device type, so it refuses to proceed without it. Device type also comes from the device token claims set at registration time.","triggerScenarios":"Calling POST /devices/lost-trust with a device token that carries an identifier claim but no device-type claim. The earlier DeviceIdentifier check passes, then the DeviceType null check fires.","commonSituations":"Device registered/registered-token minted before the device-type claim was added; a token forged or partially built in tests; an old client that registered a device without sending a DeviceType and is now using a token lacking that claim.","solutions":["Re-register the device supplying a valid DeviceType so the device token includes the type claim.","Ensure the client sends the DeviceType field when registering/reviving the device token.","Refresh the access token after registration so the type claim is present."],"exampleFix":"// before: device registered without a type, token has no device-type claim\n//\n// after: register with an explicit DeviceType (e.g. Mobile=0, Desktop=6, ...)\nawait deviceRepo.SaveAsync(new Device { Type = DeviceType.Android, Identifier = deviceId });","handlingStrategy":"validation","validationCode":"// Confirm the device token carries a type before calling lost-trust\nconst type = await getDeviceTypeClaim(accessToken);\nif (type == null) {\n  await reRegisterDeviceWithType(chosenDeviceType); // DeviceType.Android, etc.\n  return;\n}\nawait devicesApi.postLostTrust();","typeGuard":"function hasDeviceType(claims) { return claims?.devicetype != null; }","tryCatchPattern":"try {\n  await devicesApi.postLostTrust();\n} catch (e) {\n  if (e.status === 400 && /device type/i.test(e.message)) {\n    await reRegisterDeviceWithType(currentDeviceType);\n  } else throw e;\n}","preventionTips":["Always send a DeviceType when registering/refreshing a device token.","Refresh the access token after registration so the type claim is present.","Keep device tokens current; old tokens minted before the type claim was added will fail."],"tags":["devices","auth","current-context","http-400","lost-trust"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}