When does a Quaternion become invalid?

So my code suddenly threw the following error in the OnDrawGizmos() method Quaternion To Matrix conversion failed because input Quaternion is invalid {0.000000, 0.819208, 0.000000, 0.573472} l=0.999972 caused by Matrix4x4.TRS.
I narrowed the problem to the small test case by manually typing in the Quaternion values:

	void Start () {
        Quaternion quat = new Quaternion(0, 0.8192084f, 0, 0.5734719f);
        Debug.Log("old Quat: " + quat.eulerAngles);
        Vector3 euler = quat.eulerAngles;
        Quaternion quat2 = Quaternion.Euler(euler);
        Debug.Log("new Quat " + quat2.eulerAngles);
        Vector3 pos = Vector3.right;
        Vector3 scale = Vector3.one;

        Matrix4x4 mat2 = Matrix4x4.TRS(pos, quat2, scale);
        Matrix4x4 mat1 = Matrix4x4.TRS(pos, quat, scale);
    }

Now, what’s interesting: The last line throws the error mentioned above, the line second to last doesn’t !!!
So apparently there is some rounding going on when converting the Quaternion to Euler Angles and back to Quaternion. Still I’d love to have some explanation when a Quaternion is valid and when not?

Sure, your first quaternion isn’t properly normalized. It has a length of “0.999971882048”, though since float doesn’t have that many digits it’s rounded to “0.9999862”. printing the eulerangles makes not much sense as they are calculated from the quaternion. If you want to compare the values, use

Debug.Log("old Quat: " + quat.ToString("F10"));

This will print the quaternion values with 10 decimal places. The result is:

old Quat: (0.0000000000, 0.8192084000, 0.0000000000, 0.5734719000)
new Quat: (0.0000000000, 0.8192197000, 0.0000000000, 0.5734798000)

The new quaternion has a length of about “0.9999909369577”. Represented as a float will round to “1.0”

edit
If you want to properly normalize your quaternion, you can use this extension method:

public static class QuaternionExt
{
    public static Quaternion GetNormalized(this Quaternion q)
    {
        float f = 1f / Mathf.Sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
        return new Quaternion(q.x*f, q.y*f, q.z*f, q.w*f);
    }
}

With that class somewhere in your project you can simply do

quat = quat.GetNormalized();

Running your test with the normalized quaternion doesn’t create the error and both (quat and quat2) have the same values.