amruthpillai/reactive-resume · error · Error

Public style projection does not match the resume render dat

Error message

Public style projection does not match the resume render data

What it means

resolvePublicStyleProjectionRuntime validates the supplied PublicStyleProjection against the current resume render data via validatePublicStyleProjection; if it fails (the projection no longer matches the data) it throws. This catches stale projections used to render or re-project a resume whose underlying data changed.

Source

Thrown at packages/pdf/src/semantic/public-projection.ts:355

	attributes: { ...node.attributes },
	roles: [...node.roles],
	children: node.children
		.map((child, sourceIndex) => ({ child, sourceIndex, structure: nodes[child.key] }))
		.filter(({ structure }) => !structure?.hidden)
		.sort(
			(left, right) =>
				(left.structure?.order ?? left.sourceIndex) - (right.structure?.order ?? right.sourceIndex) ||
				left.sourceIndex - right.sourceIndex,
		)
		.map(({ child }) => applyProjectedStructure(child, nodes)),
});

export async function resolvePublicStyleProjectionRuntime(
	data: ResumeData,
	projection: PublicStyleProjection,
): Promise<ResolvedResumeRuntime> {
	if (!(await validatePublicStyleProjection(data, projection))) {
		throw new Error("Public style projection does not match the resume render data");
	}
	const projectionData = dataForPublicProjection(data, projection.languageVersion);
	const base = resolveResumeRuntime({
		data: projectionData,
		template: projectionData.metadata.template,
		mode: "legacy",
	});
	return {
		presentation: toResolvedPresentation(projection.nodes),
		sourceTree: base.sourceTree,
		renderTree: applyProjectedStructure(base.sourceTree, projection.nodes),
		diagnostics: [],
	};
}

View on GitHub (pinned to 3a5b12e2a4)

Solutions

  1. Regenerate the projection from current data via createPublicStyleProjection before resolving it.
  2. Invalidate cached projections whenever the resume's renderDataVersion / template / language changes.
  3. Persist the data fingerprint with the projection and reject mismatches client-side before calling resolve.

Example fix

// before: reuse a cached projection
await resolvePublicStyleProjectionRuntime(data, cachedProjection);
// after: regenerate when fingerprint differs
if (!(await validatePublicStyleProjection(data, cachedProjection))) {
  cachedProjection = await createPublicStyleProjection({ data });
}
await resolvePublicStyleProjectionRuntime(data, cachedProjection);
Defensive patterns

Strategy: validation

Validate before calling

if (!(await validatePublicStyleProjection(data, projection))) {
  projection = await createPublicStyleProjection({ data });
}

Type guard

async function projectionMatches(data: ResumeData, p: PublicStyleProjection): Promise<boolean> {
  return validatePublicStyleProjection(data, p);
}

Try / catch

try { await resolvePublicStyleProjectionRuntime(data, projection); }
catch (e) {
  if (/does not match the resume render data/i.test(String((e as Error).message)))) {
    projection = await createPublicStyleProjection({ data });
    await resolvePublicStyleProjectionRuntime(data, projection);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Loading a cached/stored projection after the resume's structure (sections, template, language version) changed; passing a projection that belongs to a different resume; the renderDataVersion fingerprint drifted.

Common situations: Browser cached a projection across an edit; a shared-link path that stored the projection and the owner later edited the resume; migration changed node keys so the projection's fingerprints no longer align.

Related errors


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