can1357/oh-my-pi · error · ParseError

Diff does not contain any lines

Error message

Diff does not contain any lines

What it means

parseOneHunk in the unified-diff parser throws when asked to parse a hunk from an empty remaining line list. It is the boundary guard for a diff that ends (or a hunk header that points past the end) with no hunk body lines available.

Source

Thrown at packages/coding-agent/src/edit/diff.ts:558

		changeContext: changeContext && changeContext.length > 0 ? changeContext : undefined,
	};
}

function isUnifiedDiffMetadataLine(line: string): boolean {
	return matchesTrimmedPrefix(
		line,
		DIFF_METADATA_PREFIXES.filter(prefix => !prefix.startsWith("*** ")),
	);
}

interface ParseHunkResult {
	hunk: DiffHunk;
	linesConsumed: number;
}

function parseOneHunk(lines: string[], lineNumber: number, allowMissingContext: boolean): ParseHunkResult {
	if (lines.length === 0) {
		throw new ParseError("Diff does not contain any lines", lineNumber);
	}

	const changeContexts: string[] = [];
	let oldStartLine: number | undefined;
	let newStartLine: number | undefined;
	let startIndex: number;

	const headerLine = lines[0];
	const headerTrimmed = headerLine.trimEnd();
	const isHeaderLine = headerLine.startsWith("@@");
	const unifiedHeader = isHeaderLine ? parseUnifiedHunkHeader(headerTrimmed) : undefined;
	const isEmptyContextMarker = /^@@\s*@@$/.test(headerTrimmed);

	if (isHeaderLine && (headerTrimmed === EMPTY_CHANGE_CONTEXT_MARKER || isEmptyContextMarker)) {
		startIndex = 1;
	} else if (unifiedHeader) {
		if (unifiedHeader.oldStartLine < 1 || unifiedHeader.newStartLine < 1) {
			throw new ParseError("Line numbers in @@ header must be >= 1", lineNumber);

View on GitHub (pinned to 9690622007)

Solutions

  1. Ensure the diff contains complete hunks: each @@ header followed by its body lines
  2. Check for truncation at the source (clipboard, token limit, log capture) and regenerate the diff
  3. Validate the diff is non-empty before invoking the applier
  4. Catch ParseError and surface 'diff is truncated/empty' to the user

Example fix

// before
await applyLegacyPatch('@@ -1,1 +1,2 @@'); // header with no body
// after
await applyLegacyPatch('@@ -1,1 +1,2 @@\n-old line\n+new line');
Defensive patterns

Strategy: validation

Validate before calling

if (!diffText.includes('@@') || diffText.split('\n').filter(l => l.trim()).length < 2) {
	throw new SkipOperation('diff is empty or header-only');
}

Type guard

function hasHunkBody(diffText) {
	const lines = diffText.split('\n');
	const i = lines.findIndex(l => l.startsWith('@@'));
	return i !== -1 && i + 1 < lines.length && /^[+\- ]/.test(lines[i + 1]);
}

Try / catch

try {
	await applyLegacyPatch(diffText);
} catch (err) {
	if (err instanceof ParseError && err.message === 'Diff does not contain any lines') {
		// surface 'diff is truncated or empty'
	}
}

Prevention

When it happens

Trigger: Calling the diff parser (via applyLegacyPatch/parse paths) on a diff whose @@ hunk header is the last line, or a diff body with zero lines — the hunk parser is invoked with lines.length === 0.

Common situations: Unified diff truncated right after an @@ header; empty diff file passed to the applier; a tool generated a header-only diff; line-count mismatches after CR/LF stripping left no body lines.

Related errors


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