remotion-dev/remotion · warning · Error

The provided matrix is not a valid rotation matrix.

Error message

The provided matrix is not a valid rotation matrix.

What it means

The TKHD (Track Header) parser extracts a 2x2 sub-matrix from the 3x3 transformation matrix to derive a rotation angle. It validates that the rows are unit length (a*a+b*b ≈ 1 and c*c+d*d ≈ 1); if not, the matrix is not a pure rotation and the throw fires. The earlier all-zero guard returns 0 (no rotation), so this throw only hits when the matrix has non-zero but non-orthogonal values.

Source

Thrown at packages/media-parser/src/containers/iso-base-media/tkhd.ts:35

	width: number;
	height: number;
	unrotatedWidth: number;
	unrotatedHeight: number;
	rotation: number;
}

type Matrix2x2 = readonly [number, number, number, number];

function getRotationAngleFromMatrix(matrix: Matrix2x2): number {
	// Extract elements from the matrix
	const [a, b, c, d] = matrix;
	if (a === 0 && b === 0 && c === 0 && d === 0) {
		return 0;
	}

	// Check if the matrix is a valid rotation matrix
	if (Math.round(a * a + b * b) !== 1 || Math.round(c * c + d * d) !== 1) {
		throw new Error('The provided matrix is not a valid rotation matrix.');
	}

	// Calculate the angle using the atan2 function
	const angleRadians = Math.atan2(c, a); // atan2(sin(θ), cos(θ))
	const angleDegrees = angleRadians * (180 / Math.PI); // Convert radians to degrees

	return angleDegrees;
}

const applyRotation = ({
	matrix,
	width,
	height,
}: {
	matrix: Matrix2x2;
	width: number;
	height: number;
}) => {

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Inspect the tkhd matrix with `mp4dump input.mp4 | grep -A12 tkhd`.
  2. Re-mux: `ffmpeg -i input.mp4 -c copy -movflags +faststart remuxed.mp4` to normalize the matrix to identity or a clean rotation.
  3. Apply rotation via ffmpeg metadata if rotation metadata is needed: `ffmpeg -i input.mp4 -c copy -metadata:s:v:0 rotate=0 out.mp4`.
  4. Transcode to regenerate tkhd: `ffmpeg -i input.mp4 -c:v libx264 out.mp4`.

Example fix

// before: tkhd has skew/scale matrix that fails unit-length check
ffmpeg -i input.mp4 -c copy -movflags +faststart remuxed.mp4
// after: tkhd matrix is identity or clean rotation
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the tkhd 2x2 sub-matrix is a valid rotation before parsing
function isValidRotationMatrix(a: number, b: number, c: number, d: number): boolean {
  if (a === 0 && b === 0 && c === 0 && d === 0) return true;
  return Math.round(a*a + b*b) === 1 && Math.round(c*c + d*d) === 1;
}

Type guard

type Matrix2x2 = readonly [number, number, number, number];
function isValidRotationMatrix(m: Matrix2x2): boolean {
  const [a, b, c, d] = m;
  if (a === 0 && b === 0 && c === 0 && d === 0) return true;
  return Math.round(a*a + b*b) === 1 && Math.round(c*c + d*d) === 1;
}

Try / catch

try {
  await parseMedia({src, fields: {dimensions: true}});
} catch (err) {
  if (err instanceof Error && err.message.includes('not a valid rotation matrix')) {
    // tkhd has skew/scale matrix; re-mux to normalize or transcode
  } else throw err;
}

Prevention

When it happens

Trigger: A tkhd matrix whose upper-left 2x2 block is non-zero but not a valid rotation (rows not unit length). This can happen with files that embed a skew, scale, or perspective matrix instead of a pure rotation, or with corrupted matrix bytes.

Common situations: Files from non-standard encoders that write scale or shear transforms into the tkhd matrix; corrupt tkhd data; or files with intentionally identity-but-not-unit matrices. The round() tolerance means small floating-point drift is tolerated, so genuine corruption is the usual cause.

Related errors


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