{"record":{"id":"f310c2585a351f53","repo":"amruthpillai/reactive-resume","slug":"public-style-projection-does-not-match-the-resume","errorCode":null,"errorMessage":"Public style projection does not match the resume render data","messagePattern":"Public style projection does not match the resume render data","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/pdf/src/semantic/public-projection.ts","lineNumber":355,"sourceCode":"\tattributes: { ...node.attributes },\n\troles: [...node.roles],\n\tchildren: node.children\n\t\t.map((child, sourceIndex) => ({ child, sourceIndex, structure: nodes[child.key] }))\n\t\t.filter(({ structure }) => !structure?.hidden)\n\t\t.sort(\n\t\t\t(left, right) =>\n\t\t\t\t(left.structure?.order ?? left.sourceIndex) - (right.structure?.order ?? right.sourceIndex) ||\n\t\t\t\tleft.sourceIndex - right.sourceIndex,\n\t\t)\n\t\t.map(({ child }) => applyProjectedStructure(child, nodes)),\n});\n\nexport async function resolvePublicStyleProjectionRuntime(\n\tdata: ResumeData,\n\tprojection: PublicStyleProjection,\n): Promise<ResolvedResumeRuntime> {\n\tif (!(await validatePublicStyleProjection(data, projection))) {\n\t\tthrow new Error(\"Public style projection does not match the resume render data\");\n\t}\n\tconst projectionData = dataForPublicProjection(data, projection.languageVersion);\n\tconst base = resolveResumeRuntime({\n\t\tdata: projectionData,\n\t\ttemplate: projectionData.metadata.template,\n\t\tmode: \"legacy\",\n\t});\n\treturn {\n\t\tpresentation: toResolvedPresentation(projection.nodes),\n\t\tsourceTree: base.sourceTree,\n\t\trenderTree: applyProjectedStructure(base.sourceTree, projection.nodes),\n\t\tdiagnostics: [],\n\t};\n}\n","sourceCodeStart":337,"sourceCodeEnd":370,"githubUrl":"https://github.com/amruthpillai/reactive-resume/blob/3a5b12e2a40374a9571988701fcb75c5a1831c42/packages/pdf/src/semantic/public-projection.ts#L337-L370","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Regenerate the projection from current data via createPublicStyleProjection before resolving it.","Invalidate cached projections whenever the resume's renderDataVersion / template / language changes.","Persist the data fingerprint with the projection and reject mismatches client-side before calling resolve."],"exampleFix":"// before: reuse a cached projection\nawait resolvePublicStyleProjectionRuntime(data, cachedProjection);\n// after: regenerate when fingerprint differs\nif (!(await validatePublicStyleProjection(data, cachedProjection))) {\n  cachedProjection = await createPublicStyleProjection({ data });\n}\nawait resolvePublicStyleProjectionRuntime(data, cachedProjection);","handlingStrategy":"validation","validationCode":"if (!(await validatePublicStyleProjection(data, projection))) {\n  projection = await createPublicStyleProjection({ data });\n}","typeGuard":"async function projectionMatches(data: ResumeData, p: PublicStyleProjection): Promise<boolean> {\n  return validatePublicStyleProjection(data, p);\n}","tryCatchPattern":"try { await resolvePublicStyleProjectionRuntime(data, projection); }\ncatch (e) {\n  if (/does not match the resume render data/i.test(String((e as Error).message)))) {\n    projection = await createPublicStyleProjection({ data });\n    await resolvePublicStyleProjectionRuntime(data, projection);\n    return;\n  }\n  throw e;\n}","preventionTips":["Store a data fingerprint with each cached projection and reject mismatches.","Invalidate cached projections on renderDataVersion/template/language change.","Regenerate rather than reuse stale projections."],"tags":["stylesheet","semantic","projection","cache-invalidation","pdf"],"backgroundTag":null,"analyzedSha":"3a5b12e2a40374a9571988701fcb75c5a1831c42","analyzedAt":"2026-08-12T22:31:22.666Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}