CoplayDev/unity-mcp · error · JsonSerializationException

Cannot deserialize Quaternion from {token.Type}: '{token}'

Error message

Cannot deserialize Quaternion from {token.Type}: '{token}'

What it means

Thrown by QuaternionConverter.ReadJson when the JSON token is neither a JArray with count >= 4 nor a JObject. Quaternion accepts [x, y, z, w] array form or {"x":..,"y":..,"z":..,"w":..} object form. Any other JSON structure is rejected.

Source

Thrown at MCPForUnity/Runtime/Serialization/UnityTypeConverters.cs:89

            writer.WriteStartObject();
            writer.WritePropertyName("x");
            writer.WriteValue(value.x);
            writer.WritePropertyName("y");
            writer.WriteValue(value.y);
            writer.WritePropertyName("z");
            writer.WriteValue(value.z);
            writer.WritePropertyName("w");
            writer.WriteValue(value.w);
            writer.WriteEndObject();
        }

        public override Quaternion ReadJson(JsonReader reader, Type objectType, Quaternion existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            JToken token = JToken.Load(reader);
            if (token is JArray arr && arr.Count >= 4)
                return new Quaternion((float)arr[0], (float)arr[1], (float)arr[2], (float)arr[3]);
            if (token is not JObject jo)
                throw new JsonSerializationException($"Cannot deserialize Quaternion from {token.Type}: '{token}'");
            return new Quaternion(
                (float)jo["x"],
                (float)jo["y"],
                (float)jo["z"],
                (float)jo["w"]
            );
        }
    }

    public class ColorConverter : JsonConverter<Color>
    {
        public override void WriteJson(JsonWriter writer, Color value, JsonSerializer serializer)
        {
            writer.WriteStartObject();
            writer.WritePropertyName("r");
            writer.WriteValue(value.r);
            writer.WritePropertyName("g");
            writer.WriteValue(value.g);

View on GitHub (pinned to c21bf496bc)

Solutions

  1. Send rotation as a 4-element quaternion array [x, y, z, w]: "rotation": [0, 0, 0, 1].
  2. Or send as object: "rotation": {"x": 0, "y": 0, "z": 0, "w": 1}.
  3. If you have Euler angles, convert to quaternion before sending (or check if the tool accepts a separate eulerRotation parameter).
  4. Ensure the array has exactly 4 elements (identity quaternion is [0,0,0,1]).

Example fix

// before (Euler angles sent as 3-element array)
params = {"rotation": [0, 90, 0]}
// after (proper quaternion)
params = {"rotation": [0, 0.7071, 0, 0.7071]}
Defensive patterns

Strategy: type-guard

Validate before calling

import math

def is_valid_quaternion(val) -> bool:
    if isinstance(val, (list, tuple)) and len(val) >= 4:
        return all(isinstance(v, (int, float)) for v in val[:4])
    if isinstance(val, dict):
        return all(k in val for k in ('x', 'y', 'z', 'w'))
    return False

def euler_to_quaternion(rx, ry, rz):
    """Convert Euler degrees to quaternion [x,y,z,w]."""
    rx, ry, rz = map(math.radians, [rx, ry, rz])
    cx, cy, cz = math.cos(rx/2), math.cos(ry/2), math.cos(rz/2)
    sx, sy, sz = math.sin(rx/2), math.sin(ry/2), math.sin(rz/2)
    return [cx*cy*cz + sx*sy*sz, sx*cy*cz - cx*sy*sz,
            cx*sy*cz + sx*cy*sz, cx*cy*sz - sx*sy*cz]

Type guard

function isQuaternion(val: unknown): val is number[] | {x:number;y:number;z:number;w:number} {
  if (Array.isArray(val) && val.length >= 4)
    return val.slice(0, 4).every(v => typeof v === 'number');
  if (val && typeof val === 'object' && 'x' in val && 'y' in val && 'z' in val && 'w' in val)
    return true;
  return false;
}

Try / catch

try
{
    var quat = serializer.Deserialize<Quaternion>(reader);
}
catch (JsonSerializationException ex) when (ex.Message.Contains("Cannot deserialize Quaternion"))
{
    return new ErrorResponse($"Quaternion must be [x,y,z,w] or {{x,y,z,w}}. Identity = [0,0,0,1].");
}

Prevention

When it happens

Trigger: Deserializing a rotation field from JSON where the value is a scalar, string, object missing the 'w' component, or an array with fewer than 4 elements. Also triggered when Euler angles are sent where a quaternion is expected.

Common situations: Client sends Euler angles (3-element array) where a quaternion (4-element) is expected; AI outputs rotation as "90" (scalar); object missing the 'w' field; confusion between Euler (Vector3) and quaternion (Vector4) representations.

Related errors


AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13). Data as JSON: /api/errors/891e5e1dc82170e1. Report an issue: GitHub.