{"record":{"id":"00fabc44e918ccac","repo":"remotion-dev/remotion","slug":"odd-rotation-angle","errorCode":null,"errorMessage":"Odd rotation angle","messagePattern":"Odd rotation angle","errorType":"exception","errorClass":"ErrorWithBacktrace","httpStatus":null,"severity":"warning","filePath":"packages/compositor/rust/rotation.rs","lineNumber":25,"sourceCode":"\n    for bytes in value.chunks(4) {\n        let i32_value = i32::from_le_bytes(bytes.try_into().unwrap());\n        i32_values.push(i32_value);\n    }\n\n    if i32_values.len() != 9 {\n        Err(std::io::Error::new(ErrorKind::Other, \"Invalid side data\"))?;\n    }\n    return get_rotation(&i32_values);\n}\n\npub fn get_rotation(displaymatrix: &[i32]) -> Result<f64, ErrorWithBacktrace> {\n    let mut theta = -(rotation_get(displaymatrix))?.round();\n\n    theta -= 360.0 * (theta / 360.0 + 0.9 / 360.0).floor();\n\n    if (theta - 90.0 * (theta / 90.0).round()).abs() > 2.0 {\n        Err(std::io::Error::new(ErrorKind::Other, \"Odd rotation angle\"))?;\n    }\n\n    return Ok(theta);\n}\n\npub fn rotation_get(matrix: &[i32]) -> Result<f64, ErrorWithBacktrace> {\n    let scale0 = (matrix[0] as f64).hypot(matrix[3] as f64);\n    let scale1 = (matrix[1] as f64).hypot(matrix[4] as f64);\n\n    if scale0 == 0.0 || scale1 == 0.0 {\n        Err(std::io::Error::new(ErrorKind::Other, \"Invalid matrix\"))?;\n    }\n\n    let rotation = (((matrix[1] as f64) / scale1).atan2((matrix[0] as f64) / scale0)) * 180.0 / PI;\n\n    return Ok(-rotation);\n}\n","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/compositor/rust/rotation.rs#L7-L43","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Strip the problematic rotation metadata on encode: `ffmpeg -i in.mp4 -metadata:s:v:0 rotate= -c copy out.mp4`.","Re-encode the source so the display matrix is orthogonal or absent.","If the angle is intended, pre-rotate the media to a clean 0/90/180/270 orientation outside Remotion."],"exampleFix":"// before: source has a 17-degree display matrix -> throws\n\n// after: strip rotation metadata before importing\n// $ ffmpeg -i in.mp4 -metadata:s:v:0 rotate= -c copy out.mp4","handlingStrategy":"validation","validationCode":"fn is_orthogonal(theta: f64) -> bool {\n    (theta - 90.0 * (theta / 90.0).round()).abs() <= 2.0\n}\nif !is_orthogonal(theta) { /* strip rotation metadata, treat as 0 */ }","typeGuard":"null","tryCatchPattern":"let rot = match get_rotation(&matrix) {\n    Ok(r) => r,\n    Err(_) => 0.0,\n};","preventionTips":["Pre-rotate sources to a clean 0/90/180/270 orientation.","Strip rotation metadata that encodes shear/skew.","Validate matrix-derived angles before relying on them."],"tags":["rust","ffmpeg","rotation","displaymatrix","corrupt-media"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}