{"record":{"id":"6ec5e922a63eecd9","repo":"remotion-dev/remotion","slug":"overlapping-source-edit-ranges","errorCode":null,"errorMessage":"Overlapping source edit ranges","messagePattern":"Overlapping source edit ranges","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/studio-codemods/src/source-edits.ts","lineNumber":554,"sourceCode":"\t\t}\n\t}\n\n\treturn edits;\n};\n\nexport const applySourceEdits = ({\n\tedits,\n\tinput,\n}: {\n\tedits: SourceEdit[];\n\tinput: string;\n}) => {\n\tconst sorted = edits.slice().sort((left, right) => right.start - left.start);\n\tlet output = input;\n\tlet previousStart = input.length + 1;\n\tfor (const edit of sorted) {\n\t\tif (edit.end > previousStart) {\n\t\t\tthrow new Error('Overlapping source edit ranges');\n\t\t}\n\n\t\toutput =\n\t\t\toutput.slice(0, edit.start) + edit.replacement + output.slice(edit.end);\n\t\tpreviousStart = edit.start;\n\t}\n\n\treturn output;\n};\n","sourceCodeStart":536,"sourceCodeEnd":564,"githubUrl":"https://github.com/remotion-dev/remotion/blob/46a3a6bf13ca367376ff18bbb06dae2e87e0d068/packages/studio-codemods/src/source-edits.ts#L536-L564","documentation":"applySourceEdits applies a list of text replacements to a source string, sorting them from last to first so earlier offsets stay valid. Before applying each edit it verifies the edit's range does not overlap the previously applied (later-in-file) edit; if edit.end extends past the previous edit's start, the ranges conflict and the library throws instead of producing silently corrupted output.","triggerScenarios":"Building a SourceEdit array where two edits share or overlap byte ranges — e.g. replacing an attribute's value while also replacing the entire element containing it, inserting text inside a range another edit replaces, or computing offsets from a stale version of the input after manual string manipulation.","commonSituations":"Composing multiple codemods' edits into one batch without deduplication; off-by-one range errors in custom edits; edits computed against different parse snapshots of the same file.","solutions":["Audit your edits for overlap: sort by start and assert each edit's end <= the next edit's start before calling applySourceEdits.","Collapse overlapping edits into one larger edit covering both changes.","Recompute all edits from a single, current parse of the input so offsets agree.","Catch the error, log the offending edit list, and re-run the transform producing fewer/coarser edits."],"exampleFix":"// before: overlapping edits\nedits.push({start: 10, end: 30, replacement: 'a'}, {start: 20, end: 25, replacement: 'b'});\n// after: merge into one non-overlapping edit\nedits.push({start: 10, end: 30, replacement: 'a + b merge'});","handlingStrategy":"validation","validationCode":"const sorted = edits.slice().sort((a, b) => a.start - b.start);\nfor (let i = 1; i < sorted.length; i++) {\n  if (sorted[i].start < sorted[i - 1].end) {\n    throw new Error(`Edits overlap at ${sorted[i].start}..${sorted[i].end}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const output = applySourceEdits({input, edits});\n} catch (err) {\n  if ((err as Error).message.includes('Overlapping')) {\n    // merge or recompute edits from a single parse\n  }\n}","preventionTips":["Compute every edit from the same parse snapshot of the input","Deduplicate and merge edits whose ranges touch or overlap","Never mix edits from different codemod passes on one input string","Validate ranges with a pre-check before calling applySourceEdits"],"tags":["codemod","source-edit","overlap","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"46a3a6bf13ca367376ff18bbb06dae2e87e0d068","analyzedAt":"2026-09-18T00:12:20.256Z","contentChangedAt":"2026-09-18T00:12:20.256Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}