{"record":{"id":"f141f4f8bb5538f0","repo":"stride3d/stride","slug":"owner-s-fieldname-must-be-normalized","errorCode":null,"errorMessage":"{owner}'s {fieldName} must be normalized","messagePattern":"(.+?)'s (.+?) must be normalized","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/BepuAndStrideExtensions.cs","lineNumber":49,"sourceCode":"    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static SVector3 ToStride(this NVector3 vec) => Unsafe.As<NVector3, SVector3>(ref vec);\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static NQuaternion ToNumeric(this SQuaternion qua) => Unsafe.As<SQuaternion, NQuaternion>(ref qua);\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static SQuaternion ToStride(this NQuaternion qua) => Unsafe.As<NQuaternion, SQuaternion>(ref qua);\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static void ValidateRange<T>(this SVector3 vec, T owner, [CallerMemberName] string? fieldName = null)\n    {\n        if (NVector3.AllWhereAllBitsSet(NVector3.IsFinite(vec)) == false)\n            throw new ArgumentOutOfRangeException($\"{owner}'s {fieldName} must be finite\");\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static void ValidateRange<T>(this SQuaternion quat, T owner, [CallerMemberName] string? fieldName = null)\n    {\n        if (quat.IsNormalized == false)\n            throw new ArgumentOutOfRangeException($\"{owner}'s {fieldName} must be normalized\");\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static void ValidateGreaterThanZeroFinite<T>(this float fp, T owner, [CallerMemberName] string? fieldName = null)\n    {\n        if (fp <= 0 || float.IsFinite(fp) == false)\n            throw new ArgumentOutOfRangeException($\"{owner}'s {fieldName} must be finite and greater than zero\");\n    }\n}\n","sourceCodeStart":31,"sourceCodeEnd":59,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/BepuAndStrideExtensions.cs#L31-L59","documentation":"ValidateRange(this SQuaternion, ...) verifies the quaternion is normalized (unit length). The physics engine expects rotation quaternions to be unit quaternions; an unnormalized one skews rotations and solver math, so it throws ArgumentOutOfRangeException naming the owner and field.","triggerScenarios":"Assigning a quaternion built from raw/unnormalized data (lerp without normalize, deserialized rotation, manual component math) to a physics-facing property guarded by this extension.","commonSituations":"Interpolating rotations without calling Normalize, loading quaternions from files/multiplied accumulations that drift from unit length, or constructing from non-orthonormal basis vectors.","solutions":["Normalize before assigning: quat = SQuaternion.Normalize(quat);","If constructing from axis/angle or basis vectors, use the proper constructor instead of raw components.","Validate/normalize quaternion data at load time for deserialized assets."],"exampleFix":"// before\nbody.Orientation = lerpedQuat; // length != 1\n// after\nbody.Orientation = SQuaternion.Normalize(lerpedQuat);","handlingStrategy":"validation","validationCode":"if (Math.Abs(quat.Length() - 1f) > 1e-4f) {\n    quat = SQuaternion.Normalize(quat);\n}","typeGuard":null,"tryCatchPattern":"try { quat.ValidateRange(this); body.Orientation = quat; } catch (ArgumentOutOfRangeException) { body.Orientation = SQuaternion.Normalize(quat); }","preventionTips":["Always Normalize after lerping/slerping or accumulating rotations","Build quaternions from axis-angle constructors rather than raw components","Normalize deserialized rotation data on load"],"tags":["physics","quaternion","validation"],"backgroundTag":"argument-out-of-range","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}