{"record":{"id":"e0ed41a7d2424b20","repo":"Comfy-Org/ComfyUI","slug":"invalid-rotation-matrix-shape-matrix-shape","errorCode":null,"errorMessage":"Invalid rotation matrix shape {matrix.shape}.","messagePattern":"Invalid rotation matrix shape (.+?)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy/ldm/depth_anything_3/transform.py","lineNumber":80,"sourceCode":"            1 - two_s * (j * j + k * k),\n            two_s * (i * j - k * r),\n            two_s * (i * k + j * r),\n            two_s * (i * j + k * r),\n            1 - two_s * (i * i + k * k),\n            two_s * (j * k - i * r),\n            two_s * (i * k - j * r),\n            two_s * (j * k + i * r),\n            1 - two_s * (i * i + j * j),\n        ),\n        -1,\n    )\n    return o.reshape(quaternions.shape[:-1] + (3, 3))\n\n\ndef mat_to_quat(matrix: torch.Tensor) -> torch.Tensor:\n    \"\"\"Convert (...,3,3) rotation matrices to quaternions (xyzw).\"\"\"\n    if matrix.size(-1) != 3 or matrix.size(-2) != 3:\n        raise ValueError(f\"Invalid rotation matrix shape {matrix.shape}.\")\n\n    batch_dim = matrix.shape[:-2]\n    m00, m01, m02, m10, m11, m12, m20, m21, m22 = torch.unbind(\n        matrix.reshape(batch_dim + (9,)), dim=-1\n    )\n\n    q_abs = _sqrt_positive_part(\n        torch.stack(\n            [\n                1.0 + m00 + m11 + m22,\n                1.0 + m00 - m11 - m22,\n                1.0 - m00 + m11 - m22,\n                1.0 - m00 - m11 + m22,\n            ],\n            dim=-1,\n        )\n    )\n","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy/ldm/depth_anything_3/transform.py#L62-L98","documentation":"mat_to_quat() converts rotation matrices to xyzw quaternions and requires the input's last two dimensions to be exactly 3x3. Any other trailing shape raises ValueError with the received shape. It is a hard precondition of the conversion math, which unbinds exactly nine matrix entries.","triggerScenarios":"Calling mat_to_quat on 4x4 pose matrices (forgetting to slice [...,:3,:3]), on (...,3) Euler angles, on batched tensors whose reshape earlier collapsed the matrix dims, or on transposed translation-augmented (3,4) tensors.","commonSituations":"Camera-pose pipelines that store homogeneous 4x4 matrices and pass them straight through; mixing up quaternion-to-matrix (output 3x3) and matrix-to-quaternion (input must be 3x3) call directions.","solutions":["Slice the rotation block first: mat_to_quat(pose[..., :3, :3]).","Verify with matrix.shape[-2:] == (3, 3) before the call when the source of the tensor is uncertain.","If input is (3,4) extrinsics, drop the translation column before converting."],"exampleFix":"# before\nq = mat_to_quat(pose_4x4)\n\n# after\nq = mat_to_quat(pose_4x4[..., :3, :3])","handlingStrategy":"type-guard","validationCode":"assert matrix.shape[-2:] == (3, 3), f\"need (...,3,3), got {tuple(matrix.shape)}\"","typeGuard":"def is_rotation_matrix_tensor(m: \"torch.Tensor\") -> bool:\n    return m.ndim >= 2 and m.shape[-2:] == (3, 3)","tryCatchPattern":null,"preventionTips":["Always slice pose[..., :3, :3] before quaternion conversion.","Keep rotation matrices (3x3) and homogeneous poses (4x4) in separately named variables."],"tags":["depth-anything-3","quaternion","shape-validation"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}