Genesis-Embodied-AI/genesis-world · error · ValueError

cap_axis must be non-zero

Error message

cap_axis must be non-zero

What it means

The cap-sphere sampling helper normalizes cap_axis to get the pole direction of the spherical cap; a zero vector cannot be normalized into a direction, so it is rejected. The norm is compared against gs.EPS, meaning near-zero axes (denormalized or extremely small components) also fail. This mirrors the radius and arc_spacing checks in the same function: all cap geometry parameters must be well-formed before sampling.

Source

Thrown at genesis/utils/geom.py:2364

    Returns
    -------
    points : np.ndarray, shape (N, 3)
        Points on the sphere surface.
    normals : np.ndarray, shape (N, 3), optional
        Normal vectors of the points. Only returned if ``return_normals`` is True.
    """
    if radius <= 0.0:
        raise ValueError(f"radius must be positive, got {radius}")
    if n_rings < 1:
        raise ValueError(f"n_rings must be >= 1, got {n_rings}")
    if arc_spacing <= 0.0:
        raise ValueError(f"probe_arc_spacing must be positive, got {arc_spacing}")

    pole = np.asarray(cap_axis, dtype=gs.np_float)
    p_norm = float(np.linalg.norm(pole))
    if p_norm < gs.EPS:
        raise ValueError("cap_axis must be non-zero")
    pole = pole / p_norm
    t0, t1 = orthogonals(pole)

    pts: list[np.ndarray] = []
    denom = max(n_rings - 1, 1)
    for i in range(n_rings):
        theta = (i / denom) * (0.5 * np.pi)
        sin_t, cos_t = np.sin(theta), np.cos(theta)
        ring_r = radius * sin_t
        circ = 2.0 * np.pi * ring_r
        if ring_r <= radius * gs.EPS:
            n_pts = 1
        else:
            n_pts = max(3, int(np.ceil(circ / arc_spacing)))
        for j in range(n_pts):
            psi = (j / n_pts) * (2.0 * np.pi)
            direction = sin_t * (np.cos(psi) * t0 + np.sin(psi) * t1) + cos_t * pole
            pts.append(radius * direction)

View on GitHub (pinned to 56e4aa5d82)

Solutions

  1. Pass an explicit unit axis such as cap_axis=[0, 0, 1].
  2. If the axis comes from a cross product, verify the inputs are not parallel before calling.
  3. If the axis is computed, fall back to a default direction when its norm falls below gs.EPS.

Example fix

# before
axis = np.cross(v1, v2)  # v1 parallel to v2 -> zero vector
pts = sample_cap_probe_points(radius=r, n_rings=5, arc_spacing=s, cap_axis=axis)
# after
axis = np.cross(v1, v2)
if np.linalg.norm(axis) < gs.EPS:
    axis = np.array([0.0, 0.0, 1.0])
pts = sample_cap_probe_points(radius=r, n_rings=5, arc_spacing=s, cap_axis=axis)
Defensive patterns

Strategy: validation

Validate before calling

axis = np.asarray(axis, dtype=gs.np_float)
assert np.linalg.norm(axis) >= gs.EPS, 'cap_axis is (near-)zero'

Prevention

When it happens

Trigger: Calling the cap-sphere sampling helper with cap_axis=[0,0,0] or [0,0,1e-12], or with an axis computed as a cross product of two (near-)parallel vectors, which yields a zero norm.

Common situations: Deriving cap_axis from surface normals of degenerate geometry, or from cross(a, b) where a and b are parallel; also passing an uninitialized np.zeros(3) default.

Related errors


AI-assisted analysis of Genesis-Embodied-AI/genesis-world@56e4aa5d82 (2026-08-28). Data as JSON: /api/errors/602a99a6677b4157. Report an issue: GitHub.