gitbutlerapp/gitbutler · error

Failed to parse patch

Error message

Failed to parse patch

What it means

Thrown by parseFileDiff when processFile (the diff-to-code-view parser) returns a falsy result for the given patch string. A non-empty patch that the parser cannot turn into a file diff structure indicates malformed, truncated, or unsupported diff content. The result is cached by version so re-parses with the same patch text are avoided.

Solutions

  1. Log/inspect the failing patch string to see why processFile rejects it (empty, truncated, or binary).
  2. Filter out empty or binary patches before calling parsePreparedDiffFile.
  3. Ensure the backend produces well-formed unified diffs; check for recent changes to the diff producer.
  4. Wrap parsePreparedDiffFile in try/catch and render a fallback 'diff unavailable' view per file.

Example fix

// before
const fileDiff = parsePreparedDiffFile(prepared);
// after
let fileDiff;
try {
  fileDiff = parsePreparedDiffFile(prepared);
} catch {
  fileDiff = null; // render fallback in the diff view
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!patch || patch.trim() === '') return null; // skip empty patches before parsing

Try / catch

try {
  const fileDiff = parsePreparedDiffFile(prepared);
} catch {
  renderDiffUnavailableFallback();
}

Prevention

When it happens

Trigger: Calling parseFileDiff (via parsePreparedDiffFile) with a patch string that processFile cannot parse — returns null/undefined.

Common situations: Truncated diff payloads from the backend, empty or whitespace-only patches slipping through preparation, binary-file diffs rendered as text, or an unsupported diff format produced by a git version change.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/9ec60c38d7f2aa98. Report an issue: GitHub.

Appendix: source

Thrown at apps/lite/ui/src/routes/project/$id/workspace/diff-view.ts:118

	selection: DiffLineSelection | null;
	fileByItemId: DiffView["fileByItemId"];
	diffStyle: DiffStyle;
}): CodeViewLineSelection | null => {
	if (!selection) return null;

	const file = fileByItemId.get(weakFileIdentityKey(selection.file));
	if (!file) return null;

	const range = selection.range ?? file.hunks[0]?.ranges[diffStyle];
	return range ? { id: file.item.id, range } : null;
};

const parseFileDiff = (
	patch: string,
	version: string,
): CodeViewDiffItem<Annotation>["fileDiff"] => {
	const parsed = processFile(patch, { cacheKey: version });
	if (!parsed) throw new Error("Failed to parse patch");

	return parsed;
};

/**
 * Prepare stable file IDs and patch versions once for both review state and
 * the rendered diff. Parsing remains separate so single-file mode only builds
 * Pierre's diff shape for the selected file.
 */
export const prepareDiffFiles = ({
	fileParent,
	changes,
	treeChangeDiffs,
}: PrepareDiffFilesDeps): Array<PreparedDiffFile> =>
	treeChangeDiffs.flatMap((treeChangeDiff, index) => {
		const change = changes[index];
		if (change === undefined || treeChangeDiff === undefined) return [];
		const file: FileAddress = { parent: fileParent, path: change.path };

View on GitHub (pinned to 58e5313667)