can1357/oh-my-pi · error · ApplyPatchError

Line hint ${hunk.oldStartLine} is out of range for ${path} (

Error message

Line hint ${hunk.oldStartLine} is out of range for ${path} (line numbers start at 1)

What it means

computeReplacements validates the hunk's @@ line hint before matching. If hunk.oldStartLine is defined and less than 1 (0 or negative), the hint cannot be a valid 1-indexed line number, so an ApplyPatchError is thrown. The hunk header must carry a start line of at least 1.

Source

Thrown at packages/coding-agent/src/edit/modes/patch.ts:1101

}

/**
 * Compute replacements needed to transform originalLines using the diff hunks.
 */
function computeReplacements(
	originalLines: string[],
	path: string,
	hunks: DiffHunk[],
	allowFuzzy: boolean,
): { replacements: Replacement[]; warnings: string[] } {
	const replacements: Replacement[] = [];
	const warnings: string[] = [];
	let lineIndex = 0;

	for (const hunk of hunks) {
		let contextIndex: number | undefined;
		if (hunk.oldStartLine !== undefined && hunk.oldStartLine < 1) {
			throw new ApplyPatchError(
				`Line hint ${hunk.oldStartLine} is out of range for ${path} (line numbers start at 1)`,
			);
		}
		if (hunk.newStartLine !== undefined && hunk.newStartLine < 1) {
			throw new ApplyPatchError(
				`Line hint ${hunk.newStartLine} is out of range for ${path} (line numbers start at 1)`,
			);
		}
		const lineHint = hunk.oldStartLine;
		const allowAggressiveFallbacks = hunk.changeContext !== undefined || lineHint !== undefined || hunk.isEndOfFile;
		const fallbackVariants = filterFallbackVariants(buildFallbackVariants(hunk), allowAggressiveFallbacks);
		if (lineHint !== undefined && hunk.changeContext === undefined && !hunk.hasContextLines) {
			lineIndex = Math.max(0, Math.min(lineHint - 1, originalLines.length - 1));
		}

		// If hunk has a changeContext, find it and adjust lineIndex
		if (hunk.changeContext !== undefined) {
			// Use hierarchical context matching for nested @@ anchors and space-separated contexts

View on GitHub (pinned to 9690622007)

Solutions

  1. Fix the hunk header to use a 1-indexed start line (e.g. `@@ -1,5 +1,6 @@`).
  2. If the target is a brand-new file, use *** Add File with no line hints instead of an Update hunk with line 0.
  3. Convert any 0-indexed line counters to 1-indexed before building the patch.
  4. Drop the line hint entirely — the patcher can locate the change by context lines alone.

Example fix

// before
@@ -0,3 +0,4 @@
 context

// after
@@ -1,3 +1,4 @@
 context
Defensive patterns

Strategy: validation

Validate before calling

if (hunk.oldStartLine !== undefined && hunk.oldStartLine < 1) {
  throw new Error(`oldStartLine must be >= 1, got ${hunk.oldStartLine}`);
}

Type guard

function hasValidOldHint(hunk: DiffHunk): boolean {
  return hunk.oldStartLine === undefined || hunk.oldStartLine >= 1;
}

Try / catch

try {
  applyPatch(patch);
} catch (err) {
  if (err instanceof ApplyPatchError && err.message.includes('Line hint') && err.message.includes('start at 1')) {
    // fix hunk headers to 1-indexed and retry once
  } else throw err;
}

Prevention

When it happens

Trigger: A diff hunk header like `@@ -0,0` or a computed oldStartLine of 0/negative is fed into computeReplacements; malformed patch generation or off-by-one conversion from 0-indexed to 1-indexed coordinates.

Common situations: Programmatic patch construction where line numbers were computed 0-indexed and passed unconverted; new-file patches mislabeled as updates; hand-edited diff headers.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/63c6629cdcf073bf. Report an issue: GitHub.