{"record":{"id":"9cbd95475a72ba27","repo":"remotion-dev/remotion","slug":"endat-prop-must-be-greater-than-startfrom-prop","errorCode":null,"errorMessage":"endAt prop must be greater than startFrom prop.","messagePattern":"endAt prop must be greater than startFrom prop\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/core/src/validate-start-from-props.ts","lineNumber":42,"sourceCode":"\t\tif (typeof endAt !== 'number') {\n\t\t\tthrow new TypeError(\n\t\t\t\t`type of endAt prop must be a number, instead got type ${typeof endAt}.`,\n\t\t\t);\n\t\t}\n\n\t\tif (isNaN(endAt)) {\n\t\t\tthrow new TypeError('endAt prop can not be NaN.');\n\t\t}\n\n\t\tif (endAt <= 0) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`endAt must be a positive number, instead got ${endAt}.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif ((endAt as number) < (startFrom as number)) {\n\t\tthrow new TypeError('endAt prop must be greater than startFrom prop.');\n\t}\n};\n\nexport const validateTrimProps = (\n\ttrimBefore: number | undefined,\n\ttrimAfter: number | undefined,\n) => {\n\tif (typeof trimBefore !== 'undefined') {\n\t\tif (typeof trimBefore !== 'number') {\n\t\t\tthrow new TypeError(\n\t\t\t\t`type of trimBefore prop must be a number, instead got type ${typeof trimBefore}.`,\n\t\t\t);\n\t\t}\n\n\t\tif (isNaN(trimBefore) || trimBefore === Infinity) {\n\t\t\tthrow new TypeError('trimBefore prop can not be NaN or Infinity.');\n\t\t}\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/core/src/validate-start-from-props.ts#L24-L60","documentation":"validateStartFromProps enforces that endAt must be greater than startFrom, otherwise the requested playback window is empty or inverted. This check runs after individual type/range checks so both values are known to be valid numbers.","triggerScenarios":"Passing both startFrom and endAt where endAt <= startFrom, e.g. startFrom={100} endAt={50}, or computed values where the trim window inverts.","commonSituations":"Swapping startFrom and endAt by mistake; computing both from a dynamic source where the ordering assumption breaks; off-by-one when startFrom and endAt are derived from separate timestamps.","solutions":["Ensure endAt is strictly greater than startFrom: startFrom={50} endAt={200}.","If computing dynamically, assert order before rendering: endAt = Math.max(endAt, startFrom + 1).","Swap the two values if they were reversed.","Migrate to trimBefore/trimAfter (same ordering constraint applies: trimAfter must exceed trimBefore)."],"exampleFix":"// before\n<Audio src={src} startFrom={100} endAt={50} />\n// after\n<Audio src={src} trimBefore={50} trimAfter={100} />","handlingStrategy":"validation","validationCode":"if (\n  startFrom !== undefined &&\n  endAt !== undefined &&\n  endAt <= startFrom\n) {\n  throw new Error('endAt must be greater than startFrom');\n}","typeGuard":"const isValidWindow = (\n  startFrom: unknown,\n  endAt: unknown,\n): boolean =>\n  typeof startFrom === 'number' &&\n  typeof endAt === 'number' &&\n  Number.isFinite(startFrom) &&\n  Number.isFinite(endAt) &&\n  endAt > startFrom;","tryCatchPattern":null,"preventionTips":["When computing both values dynamically, assert endAt > startFrom before rendering.","Derive endAt from startFrom + duration to keep ordering invariant by construction.","Prefer trimBefore/trimAfter over the deprecated pair."],"tags":["validation","props","deprecated","trimming","range"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}