remotion-dev/remotion · warning · ErrorWithBacktrace

Invalid matrix

Error message

Invalid matrix

What it means

Thrown by rotation_get when the computed scale of either matrix axis is zero, i.e. scale0 = hypot(matrix[0], matrix[3]) == 0 or scale1 = hypot(matrix[1], matrix[4]) == 0. A zero scale makes the rotation undefined (division by zero), so the function refuses.

Source

Thrown at packages/compositor/rust/rotation.rs:36

pub fn get_rotation(displaymatrix: &[i32]) -> Result<f64, ErrorWithBacktrace> {
    let mut theta = -(rotation_get(displaymatrix))?.round();

    theta -= 360.0 * (theta / 360.0 + 0.9 / 360.0).floor();

    if (theta - 90.0 * (theta / 90.0).round()).abs() > 2.0 {
        Err(std::io::Error::new(ErrorKind::Other, "Odd rotation angle"))?;
    }

    return Ok(theta);
}

pub fn rotation_get(matrix: &[i32]) -> Result<f64, ErrorWithBacktrace> {
    let scale0 = (matrix[0] as f64).hypot(matrix[3] as f64);
    let scale1 = (matrix[1] as f64).hypot(matrix[4] as f64);

    if scale0 == 0.0 || scale1 == 0.0 {
        Err(std::io::Error::new(ErrorKind::Other, "Invalid matrix"))?;
    }

    let rotation = (((matrix[1] as f64) / scale1).atan2((matrix[0] as f64) / scale0)) * 180.0 / PI;

    return Ok(-rotation);
}

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Strip or reset the display matrix: `ffmpeg -i in.mp4 -metadata:s:v:0 rotate= -c copy out.mp4`.
  2. Treat a degenerate matrix as no rotation (0 degrees) upstream instead of passing it to rotation_get.
  3. Re-encode the source to produce a clean display matrix.

Example fix

// before
let rot = get_rotation(&matrix)?; // throws on zero scale

// after: guard degenerate matrices upstream
let scale0 = (matrix[0] as f64).hypot(matrix[3] as f64);
let scale1 = (matrix[1] as f64).hypot(matrix[4] as f64);
let rot = if scale0 == 0.0 || scale1 == 0.0 { 0.0 } else { get_rotation(&matrix)? };
Defensive patterns

Strategy: validation

Validate before calling

let scale0 = (matrix[0] as f64).hypot(matrix[3] as f64);
let scale1 = (matrix[1] as f64).hypot(matrix[4] as f64);
if scale0 == 0.0 || scale1 == 0.0 { return 0.0; /* degenerate, treat as no rotation */ }

Type guard

null

Try / catch

let rot = match rotation_get(&matrix) {
    Ok(r) => r,
    Err(_) => 0.0,
};

Prevention

When it happens

Trigger: A display matrix whose first two columns are zeroed out (degenerate/identity-gone-wrong), or partially-initialized matrix entries. The guard `scale0 == 0.0 || scale1 == 0.0` fires before the atan2 division.

Common situations: Containers writing a placeholder/zero display matrix; truncated side data parsed into i32s that happen to be zero; legacy `rotate` metadata that some muxers fill with zeros.

Related errors


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/bb626ab938b68705. Report an issue: GitHub.