{"record":{"id":"891e5e1dc82170e1","repo":"CoplayDev/unity-mcp","slug":"cannot-deserialize-quaternion-from-token-type","errorCode":null,"errorMessage":"Cannot deserialize Quaternion from {token.Type}: '{token}'","messagePattern":"Cannot deserialize Quaternion from (.+?): '(.+?)'","errorType":"exception","errorClass":"JsonSerializationException","httpStatus":null,"severity":"error","filePath":"MCPForUnity/Runtime/Serialization/UnityTypeConverters.cs","lineNumber":89,"sourceCode":"            writer.WriteStartObject();\n            writer.WritePropertyName(\"x\");\n            writer.WriteValue(value.x);\n            writer.WritePropertyName(\"y\");\n            writer.WriteValue(value.y);\n            writer.WritePropertyName(\"z\");\n            writer.WriteValue(value.z);\n            writer.WritePropertyName(\"w\");\n            writer.WriteValue(value.w);\n            writer.WriteEndObject();\n        }\n\n        public override Quaternion ReadJson(JsonReader reader, Type objectType, Quaternion existingValue, bool hasExistingValue, JsonSerializer serializer)\n        {\n            JToken token = JToken.Load(reader);\n            if (token is JArray arr && arr.Count >= 4)\n                return new Quaternion((float)arr[0], (float)arr[1], (float)arr[2], (float)arr[3]);\n            if (token is not JObject jo)\n                throw new JsonSerializationException($\"Cannot deserialize Quaternion from {token.Type}: '{token}'\");\n            return new Quaternion(\n                (float)jo[\"x\"],\n                (float)jo[\"y\"],\n                (float)jo[\"z\"],\n                (float)jo[\"w\"]\n            );\n        }\n    }\n\n    public class ColorConverter : JsonConverter<Color>\n    {\n        public override void WriteJson(JsonWriter writer, Color value, JsonSerializer serializer)\n        {\n            writer.WriteStartObject();\n            writer.WritePropertyName(\"r\");\n            writer.WriteValue(value.r);\n            writer.WritePropertyName(\"g\");\n            writer.WriteValue(value.g);","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/CoplayDev/unity-mcp/blob/c21bf496bca87d54e75bad048563c3adb1782081/MCPForUnity/Runtime/Serialization/UnityTypeConverters.cs#L71-L107","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Send rotation as a 4-element quaternion array [x, y, z, w]: \"rotation\": [0, 0, 0, 1].","Or send as object: \"rotation\": {\"x\": 0, \"y\": 0, \"z\": 0, \"w\": 1}.","If you have Euler angles, convert to quaternion before sending (or check if the tool accepts a separate eulerRotation parameter).","Ensure the array has exactly 4 elements (identity quaternion is [0,0,0,1])."],"exampleFix":"// before (Euler angles sent as 3-element array)\nparams = {\"rotation\": [0, 90, 0]}\n// after (proper quaternion)\nparams = {\"rotation\": [0, 0.7071, 0, 0.7071]}","handlingStrategy":"type-guard","validationCode":"import math\n\ndef is_valid_quaternion(val) -> bool:\n    if isinstance(val, (list, tuple)) and len(val) >= 4:\n        return all(isinstance(v, (int, float)) for v in val[:4])\n    if isinstance(val, dict):\n        return all(k in val for k in ('x', 'y', 'z', 'w'))\n    return False\n\ndef euler_to_quaternion(rx, ry, rz):\n    \"\"\"Convert Euler degrees to quaternion [x,y,z,w].\"\"\"\n    rx, ry, rz = map(math.radians, [rx, ry, rz])\n    cx, cy, cz = math.cos(rx/2), math.cos(ry/2), math.cos(rz/2)\n    sx, sy, sz = math.sin(rx/2), math.sin(ry/2), math.sin(rz/2)\n    return [cx*cy*cz + sx*sy*sz, sx*cy*cz - cx*sy*sz,\n            cx*sy*cz + sx*cy*sz, cx*cy*sz - sx*sy*cz]","typeGuard":"function isQuaternion(val: unknown): val is number[] | {x:number;y:number;z:number;w:number} {\n  if (Array.isArray(val) && val.length >= 4)\n    return val.slice(0, 4).every(v => typeof v === 'number');\n  if (val && typeof val === 'object' && 'x' in val && 'y' in val && 'z' in val && 'w' in val)\n    return true;\n  return false;\n}","tryCatchPattern":"try\n{\n    var quat = serializer.Deserialize<Quaternion>(reader);\n}\ncatch (JsonSerializationException ex) when (ex.Message.Contains(\"Cannot deserialize Quaternion\"))\n{\n    return new ErrorResponse($\"Quaternion must be [x,y,z,w] or {{x,y,z,w}}. Identity = [0,0,0,1].\");\n}","preventionTips":["Remember quaternions have 4 components [x,y,z,w], not 3 (Euler).","Identity rotation is [0, 0, 0, 1].","Convert Euler angles to quaternions before sending, or check for a separate euler parameter.","Don't send a 3-element array for rotation fields."],"tags":["serialization","quaternion","json","deserialization","type-converter","rotation"],"backgroundTag":null,"analyzedSha":"c21bf496bca87d54e75bad048563c3adb1782081","analyzedAt":"2026-08-13T17:36:56.095Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}