Comfy-Org/ComfyUI · error · ValueError

Invalid affine shape: {ext.shape}

Error message

Invalid affine shape: {ext.shape}

What it means

as_homogeneous() promotes camera extrinsics to 4x4 homogeneous form. It accepts only trailing shapes (...,3,4) (promotion applied) or (...,4,4) (no-op); any other trailing two dims raise ValueError with the offending shape. This is a strict contract check on pose tensors coming from dataset/loader code.

Source

Thrown at comfy/ldm/depth_anything_3/transform.py:24

import torch
import torch.nn.functional as F


# -----------------------------------------------------------------------------
# Affine 4x4 helpers
# -----------------------------------------------------------------------------


def as_homogeneous(ext: torch.Tensor) -> torch.Tensor:
    """Promote (...,3,4) extrinsics to (...,4,4) homogeneous form. No-op when the input is already ``(...,4,4)``."""
    if ext.shape[-2:] == (4, 4):
        return ext
    if ext.shape[-2:] == (3, 4):
        ones = torch.zeros_like(ext[..., :1, :4])
        ones[..., 0, 3] = 1.0
        return torch.cat([ext, ones], dim=-2)
    raise ValueError(f"Invalid affine shape: {ext.shape}")


def affine_inverse(A: torch.Tensor) -> torch.Tensor:
    """Inverse of an affine matrix ``[R|T; 0 0 0 1]``."""
    R = A[..., :3, :3]
    T = A[..., :3, 3:]
    P = A[..., 3:, :]
    return torch.cat([torch.cat([R.mT, -R.mT @ T], dim=-1), P], dim=-2)


# -----------------------------------------------------------------------------
# Quaternion <-> rotation matrix (xyzw / scalar-last)
# -----------------------------------------------------------------------------


def _sqrt_positive_part(x: torch.Tensor) -> torch.Tensor:
    """sqrt(max(0, x)) with a zero subgradient where x == 0."""
    ret = torch.zeros_like(x)

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Convert your pose representation to (...,3,4) or (...,4,4) [R|t] form before calling (e.g. cat rotation matrix with translation column).
  2. If you have quaternions, use quat_to_mat (same module) first, then build the 3x4.
  3. Print ext.shape right before the call and fix whatever upstream reshape produced the wrong dims.

Example fix

# before (R only, shape (...,3,3))
E = as_homogeneous(R)

# after
E = as_homogeneous(torch.cat([R, t.unsqueeze(-1)], dim=-1))  # (...,3,4)
Defensive patterns

Strategy: type-guard

Validate before calling

assert ext.shape[-2:] in ((3, 4), (4, 4)), f"extrinsics must end (...,3,4) or (...,4,4), got {tuple(ext.shape)}"

Type guard

def is_affine_pose_tensor(ext: "torch.Tensor") -> bool:
    return ext.ndim >= 2 and ext.shape[-2:] in ((3, 4), (4, 4))

Prevention

When it happens

Trigger: Passing extrinsics with shapes like (...,3,3) (rotation only), (...,4) (quaternion or translation vector), (...,2,4), or non-matrix tensors. Common when a dataloader returns poses in a different convention (e.g. 4x4 already transposed to column-major, or axis-angle vectors) that was not converted first.

Common situations: Feeding DA3 ray/pose utilities with raw dataset camera poses (COLMAP/world-to-camera variants, quaternion+translation format); shapes corrupted by a wrong reshape or flatten earlier in the pipeline.

Related errors


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/e641aed2c4a67e23. Report an issue: GitHub.