{"record":{"id":"bb626ab938b68705","repo":"remotion-dev/remotion","slug":"invalid-matrix","errorCode":null,"errorMessage":"Invalid matrix","messagePattern":"Invalid matrix","errorType":"exception","errorClass":"ErrorWithBacktrace","httpStatus":null,"severity":"warning","filePath":"packages/compositor/rust/rotation.rs","lineNumber":36,"sourceCode":"\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":18,"sourceCodeEnd":43,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/compositor/rust/rotation.rs#L18-L43","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Strip or reset the display matrix: `ffmpeg -i in.mp4 -metadata:s:v:0 rotate= -c copy out.mp4`.","Treat a degenerate matrix as no rotation (0 degrees) upstream instead of passing it to rotation_get.","Re-encode the source to produce a clean display matrix."],"exampleFix":"// before\nlet rot = get_rotation(&matrix)?; // throws on zero scale\n\n// after: guard degenerate matrices upstream\nlet scale0 = (matrix[0] as f64).hypot(matrix[3] as f64);\nlet scale1 = (matrix[1] as f64).hypot(matrix[4] as f64);\nlet rot = if scale0 == 0.0 || scale1 == 0.0 { 0.0 } else { get_rotation(&matrix)? };","handlingStrategy":"validation","validationCode":"let scale0 = (matrix[0] as f64).hypot(matrix[3] as f64);\nlet scale1 = (matrix[1] as f64).hypot(matrix[4] as f64);\nif scale0 == 0.0 || scale1 == 0.0 { return 0.0; /* degenerate, treat as no rotation */ }","typeGuard":"null","tryCatchPattern":"let rot = match rotation_get(&matrix) {\n    Ok(r) => r,\n    Err(_) => 0.0,\n};","preventionTips":["Sanitize display matrices: treat zero-scale as identity.","Strip zero/placeholder rotation metadata on remux.","Re-encode sources with clean display matrices."],"tags":["rust","ffmpeg","rotation","displaymatrix","degenerate-matrix"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}