amruthpillai/reactive-resume · error · ORPCError

INVALID_PATCH_OPERATIONS

INVALID_PATCH_OPERATIONS

Error message

Failed to apply patch operations

What it means

applyResumePatchTx() wraps applyResumePatches(); if patching throws anything that is not a ResumePatchError, it is re-thrown as INVALID_PATCH_OPERATIONS with the original message. (A ResumePatchError is mapped separately with structured code/index/operation data.) This guards the JSON Patch path against arbitrary failures.

Source

Thrown at packages/api/src/features/resume/service.ts:179

		throw resumeVersionConflict(existing.updatedAt);
	}

	input.operations.forEach(assertSafePatchPointers);

	let patchedData: ResumeData;

	try {
		patchedData = applyResumePatches(existing.data, input.operations);
	} catch (error) {
		if (error instanceof ResumePatchError) {
			throw new ORPCError("INVALID_PATCH_OPERATIONS", {
				status: 400,
				message: error.message,
				data: { code: error.code, index: error.index, operation: error.operation },
			});
		}

		throw new ORPCError("INVALID_PATCH_OPERATIONS", {
			status: 400,
			message: error instanceof Error ? error.message : "Failed to apply patch operations",
		});
	}

	patchedData = parseWritableResumeData(preserveServerStylesheet(existing.data, patchedData));
	if (
		existing.data.metadata.stylesheet?.mode === "semantic" &&
		JSON.stringify(existing.data.metadata.styleRules) !== JSON.stringify(patchedData.metadata.styleRules)
	) {
		throw invalidPatchOperation("Legacy style rules cannot be changed while Semantic CSS mode is active.");
	}

	const renderDataChanged = hasRenderDataChanged(existing.data, patchedData);
	const [resume] = await client
		.update(schema.resume)
		.set({
			data: patchedData,

View on GitHub (pinned to 3a5b12e2a4)

Solutions

  1. Validate operations against the JSON Patch schema and run assertSafePatchPointers before submitting.
  2. Inspect error.message (and for a ResumePatchError, error.data.code/index/operation) to find the offending op.
  3. Reduce the batch to a single op to isolate the failing operation.

Example fix

// before
resumeService.patch({ id, userId, operations: [{ op: 'replace', path: 'basics.name', value: 123 }] });
// after
import { parseResumeData } from '@reactive-resume/schema/resume/data';
// ensure value types match the schema; strings stay strings
resumeService.patch({ id, userId, operations: [{ op: 'replace', path: 'basics.name', value: 'Jane Doe' }] });
Defensive patterns

Strategy: validation

Validate before calling

function assertSafeOperations(operations) {
  for (const op of operations) {
    if (!['add','remove','replace','move','copy','test'].includes(op.op)) throw new Error(`Bad op: ${op.op}`);
    if (typeof op.path !== 'string' || !op.path.startsWith('/')) throw new Error(`Bad path: ${op.path}`);
  }
}

Type guard

function isJsonPatchOperation(value: unknown): value is { op: string; path: string; value?: unknown } {
  return typeof value === 'object' && value !== null && typeof (value as any).op === 'string' && typeof (value as any).path === 'string';
}

Try / catch

try {
  await resumeService.patch({ id, userId, operations });
} catch (e) {
  if (e.code === 'INVALID_PATCH_OPERATIONS') {
    // e.data may carry { code, index, operation } for a ResumePatchError
    console.error('Patch op failed at index', e.data?.index, e.data?.operation);
  } else throw e;
}

Prevention

When it happens

Trigger: A JSON Patch operation whose 'path' or structure triggers a non-ResumePatchError exception — e.g. an internal assertion, a type error in the patch engine, or an operation the resume patch layer doesn't support.

Common situations: A malformed op object, an outdated client building patches against an older resume shape, or a bug in the patch library.

Related errors


AI-assisted analysis of amruthpillai/reactive-resume@3a5b12e2a4 (2026-08-12). Data as JSON: /api/errors/ad96e2e38ba80348. Report an issue: GitHub.