remotion-dev/remotion · warning · ErrorWithBacktrace

Odd rotation angle

Error message

Odd rotation angle

What it means

Thrown by get_rotation when the normalized rotation angle is not within 2 degrees of a multiple of 90. Remotion only supports orthogonal rotations; arbitrary angles indicate a malformed display matrix or unsupported rotation metadata.

Source

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

    for bytes in value.chunks(4) {
        let i32_value = i32::from_le_bytes(bytes.try_into().unwrap());
        i32_values.push(i32_value);
    }

    if i32_values.len() != 9 {
        Err(std::io::Error::new(ErrorKind::Other, "Invalid side data"))?;
    }
    return get_rotation(&i32_values);
}

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 the problematic rotation metadata on encode: `ffmpeg -i in.mp4 -metadata:s:v:0 rotate= -c copy out.mp4`.
  2. Re-encode the source so the display matrix is orthogonal or absent.
  3. If the angle is intended, pre-rotate the media to a clean 0/90/180/270 orientation outside Remotion.

Example fix

// before: source has a 17-degree display matrix -> throws

// after: strip rotation metadata before importing
// $ ffmpeg -i in.mp4 -metadata:s:v:0 rotate= -c copy out.mp4
Defensive patterns

Strategy: validation

Validate before calling

fn is_orthogonal(theta: f64) -> bool {
    (theta - 90.0 * (theta / 90.0).round()).abs() <= 2.0
}
if !is_orthogonal(theta) { /* strip rotation metadata, treat as 0 */ }

Type guard

null

Try / catch

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

Prevention

When it happens

Trigger: A display matrix that encodes a skew/non-orthogonal transform, or numeric corruption in the matrix entries producing a theta far from 0/90/180/270. The check `(theta - 90*round(theta/90)).abs() > 2.0` is the guard.

Common situations: Hand-edited or transcode-artifact display matrices; sources with perspective/shear encoded as rotation; rare codec/container bugs that write garbage into the display matrix.

Related errors


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