{"record":{"id":"eb38d2e11ce3a834","repo":"heygen-com/hyperframes","slug":"cannot-merge-a-grading-patch-into-an-unresolved-wh","errorCode":null,"errorMessage":"Cannot merge a grading patch into an unresolved whole-grade variable","messagePattern":"Cannot merge a grading patch into an unresolved whole-grade variable","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/media-treatment.ts","lineNumber":391,"sourceCode":"  } catch {\n    return raw;\n  }\n}\n\nfunction mergeGradingPatch(current: unknown, patch: unknown): unknown {\n  if (!isRecord(current) || !isRecord(patch)) return patch;\n  const merged = { ...current };\n  for (const [key, value] of Object.entries(patch)) {\n    merged[key] =\n      isRecord(value) && isRecord(merged[key]) ? mergeGradingPatch(merged[key], value) : value;\n  }\n  return merged;\n}\n\nfunction serializeGradingPatch(before: unknown, patch: unknown): string | null {\n  assertKnownGradingShape(patch);\n  if (isColorGradingVariableRef(before) && isRecord(patch)) {\n    throw new Error(\"Cannot merge a grading patch into an unresolved whole-grade variable\");\n  }\n  const current =\n    typeof before === \"string\" && !isColorGradingVariableRef(before) ? { preset: before } : before;\n  const grading = mergeGradingPatch(current, patch);\n  assertKnownGradingShape(grading);\n  if (containsColorGradingVariableRef(grading)) {\n    return typeof grading === \"string\" ? grading.trim() : JSON.stringify(grading);\n  }\n  const normalized = normalizeHfColorGrading(grading);\n  if (!normalized) throw new Error(\"--grading must be valid HyperFrames color-grading JSON\");\n  return hasHfColorGradingAuthoredValues(normalized) ? serializeHfColorGrading(normalized) : null;\n}\n\nfunction queryIncludingTemplates(root: Document | Element, selector: string): Element[] {\n  const matches = Array.from(root.querySelectorAll(selector));\n  if (matches.length > 0) return matches;\n  for (const template of root.querySelectorAll(\"template\")) {\n    const nested = queryIncludingTemplates(template, selector);","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/media-treatment.ts#L373-L409","documentation":"Thrown by serializeGradingPatch() in packages/cli/src/commands/media-treatment.ts:388. Before merging, it checks: if the existing stored value (before) is a color-grading variable reference (a '${...}' string) AND the incoming patch is a record/object, it refuses to merge. A variable ref is an opaque whole-grade slot; merging partial keys into it would silently drop the reference.","triggerScenarios":"The target element's data-hf-color-grading attribute is a variable reference (e.g. \"${grade.hero}\"), and you call --apply with --grading as an object patch without first clearing the ref.","commonSituations":"Composition authored with reusable grade variables; an agent trying to tune one control on an element that's already bound to a variable; refactoring a project that uses palette/grade variables.","solutions":["Clear the existing ref first: `--clear`, then apply a fresh full grading object.","Or supply a complete grading object that wholesale replaces the variable ref instead of a partial patch.","Resolve the variable to concrete values at the source (where it's defined) and re-apply.","If you intended to keep the variable, edit the variable definition directly rather than the element attribute."],"exampleFix":"# element currently: <img data-hf-color-grading=\"${grade.hero}\">\n# before -- refused\nhyperframes media-treatment -s '#hero' --grading '{\"wheels\":{...}}' --apply\n# after -- clear the ref, then apply a full object\nhyperframes media-treatment -s '#hero' --clear\nhyperframes media-treatment -s '#hero' --grading '{\"preset\":\"warm-daylight\",\"intensity\":0.6}' --apply","handlingStrategy":"type-guard","validationCode":"import { isColorGradingVariableRef } from '@hyperframes/parsers/color-grading-contract';\nimport { parseStoredGrading } from './grading.js';\n\nfunction canMergeInto(before: unknown, patch: unknown): boolean {\n  return !(isColorGradingVariableRef(before) && patch !== null && typeof patch === 'object');\n}","typeGuard":"import { isColorGradingVariableRef } from '@hyperframes/parsers/color-grading-contract';\n\nfunction isWholeGradeVariableRef(value: unknown): value is string {\n  return isColorGradingVariableRef(value);\n}","tryCatchPattern":"try {\n  serializeGradingPatch(before, patch);\n} catch (error) {\n  if (/Cannot merge a grading patch into an unresolved whole-grade variable/.test(String(error))) {\n    // clear the ref first, then apply a full replacement object\n    serializeGradingPatch(null, fullGradingObject);\n  } else throw error;\n}","preventionTips":["Check isColorGradingVariableRef(before) before sending an object patch; if true, send a full object or clear first.","Don't author element-level variable refs if agents will patch individual controls.","Run --dry-run --json to detect this before writing."],"tags":["color-grading","validation","media-treatment"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}