can1357/oh-my-pi · error · ApplyPatchError

Refusing partial-line match in ${path} at line ${matchStartI

Error message

Refusing partial-line match in ${path} at line ${matchStartIndex + j + 1}: the file line also contains ${JSON.stringify(part)}, which the replacement would silently drop. Provide the complete line in the hunk.

What it means

During a fuzzy/substring sequence match, the matched hunk lines covered only part of one or more whole file lines (assertPartialMatchPreservesDiscardedText). Applying a whole-line replacement would delete the extra text that was in the file line but absent from the hunk, so the patcher refuses instead of silently dropping it. The fix is to include the complete file line(s) in the hunk's removed lines.

Source

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

	path: string,
	pattern: string[],
	matchedLines: string[],
	newLines: string[],
	matchStartIndex: number,
): void {
	let newLinesNorm: string | undefined;
	for (let j = 0; j < pattern.length; j++) {
		const lineNorm = normalizeForFuzzy(matchedLines[j]);
		const patternNorm = normalizeForFuzzy(pattern[j]);
		if (lineNorm === patternNorm) continue;
		const at = lineNorm.indexOf(patternNorm);
		if (at === -1) continue;
		const discardedParts = [lineNorm.slice(0, at).trim(), lineNorm.slice(at + patternNorm.length).trim()];
		for (const part of discardedParts) {
			if (part.length === 0) continue;
			newLinesNorm ??= newLines.map(normalizeForFuzzy).join("\n");
			if (!newLinesNorm.includes(part)) {
				throw new ApplyPatchError(
					`Refusing partial-line match in ${path} at line ${matchStartIndex + j + 1}: ` +
						`the file line also contains ${JSON.stringify(part)}, which the replacement would silently drop. ` +
						`Provide the complete line in the hunk.`,
				);
			}
		}
	}
}

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

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-read the file at the reported line and copy the complete line verbatim into the hunk's removed lines.
  2. Add the missing remainder text to the replacement lines so nothing is dropped.
  3. Increase surrounding context in the hunk so an exact whole-line match is found instead of a substring strategy.
  4. Reduce reliance on fuzzy matching: provide the exact original line including whitespace/modifiers.

Example fix

// before (hunk line: 'foo = 1' matching file line 'public foo = 1; // count')
-  foo = 1
+  foo = 2

// after
-  public foo = 1; // count
+  public foo = 2; // count
Defensive patterns

Strategy: validation

Validate before calling

const fileLines = (await Bun.file(path).text()).split('\n');
const target = fileLines[lineNo - 1] ?? '';
if (!hunk.oldLines.some(l => l.trim() === target.trim())) {
  // file line is longer than hunk line: copy the full file line into the hunk
  hunk.oldLines = [target];
}

Try / catch

try {
  applyPatch(patch);
} catch (err) {
  if (err instanceof ApplyPatchError && err.message.includes('Refusing partial-line match')) {
    // re-read file at the reported line and rebuild the hunk with complete lines
  } else throw err;
}

Prevention

When it happens

Trigger: A hunk's old lines match a substring/prefix of a longer file line (e.g. the model wrote `foo = 1` while the file has `public foo = 1;`), and the leftover text (before or after the matched part) does not appear anywhere in the hunk's new lines.

Common situations: Model abbreviated a line it saw truncated; file line has decorators, visibility modifiers, or trailing comments the hunk omitted; tab/space normalization partially aligns a long line; editing minified or unusually long single-line code.

Related errors


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