heygen-com/hyperframes · error · Error
Grade entry "${label}" must include a grading value
Error message
Grade entry "${label}" must include a grading value What it means
Thrown by parseGradesFile when a grades-JSON array entry has a valid `label` string but is missing the `grading` key. Each entry MUST be shaped `{ label, grading }`; the `grading` value is what feeds the color-grading shader, so an entry without it carries nothing to render. The check uses hasOwn, so an explicit `"grading": undefined` also trips it.
Source
Thrown at packages/cli/src/commands/grade-compare.ts:233
parsed = JSON.parse(readFileSync(filePath, "utf-8"));
} catch (err) {
throw new Error(`Could not parse grades JSON: ${normalizeErrorMessage(err)}`);
}
if (!Array.isArray(parsed)) {
throw new Error("Grades file must be a JSON array of { label, grading } objects");
}
return parsed.map((entry, index) => {
if (!isRecord(entry)) {
throw new Error(`Grade entry ${index + 1} must be an object with label and grading`);
}
const label = entry.label;
if (typeof label !== "string" || !label.trim()) {
throw new Error(`Grade entry ${index + 1} must have a non-empty string label`);
}
if (!hasOwn(entry, "grading")) {
throw new Error(`Grade entry "${label}" must include a grading value`);
}
return validateCell(label, entry.grading);
});
}
export function resolveLutCells(luts: string): GradeCompareCell[] {
const paths = luts
.split(",")
.map((part) => part.trim())
.filter(Boolean);
if (paths.length === 0) {
throw new Error("--luts must include at least one LUT path");
}
return paths.map((lutPath) =>
validateCell(basename(lutPath, extname(lutPath)), { lut: { src: lutPath } }),
);
}
View on GitHub (pinned to c2996c8626)
Solutions
- Open grades.json and add a `grading` object to the entry named in the message, e.g. `{"label":"Warm","grading":{"brightness":0.1}}`.
- If unsure of the grading shape, run `hyperframes grade-compare --for frame.png --luts x.cube` once to see a valid cell, or consult the color-grading docs for the accepted keys.
- Lint the file before running: every top-level array element must own both `label` (non-empty string) and `grading`.
Example fix
// before — grades.json
[{"label":"Warm"}]
// after
[{"label":"Warm","grading":{"brightness":0.1,"contrast":1.1}}] Defensive patterns
Strategy: validation
Validate before calling
// Validate a grades file before calling parseGradesFile
import { readFileSync } from "node:fs";
function validateGradesFile(path: string): void {
const parsed = JSON.parse(readFileSync(path, "utf-8"));
if (!Array.isArray(parsed)) throw new Error("grades file must be a JSON array");
for (let i = 0; i < parsed.length; i++) {
const e = parsed[i];
if (typeof e !== "object" || e === null || Array.isArray(e))
throw new Error(`entry ${i + 1} is not an object`);
if (typeof e.label !== "string" || !e.label.trim())
throw new Error(`entry ${i + 1} lacks a non-empty label`);
if (!Object.prototype.hasOwnProperty.call(e, "grading"))
throw new Error(`entry ${i + 1} ("${e.label}") lacks grading`);
}
} Type guard
function isGradeEntry(v: unknown): v is { label: string; grading: unknown } {
return typeof v === "object" && v !== null && !Array.isArray(v)
&& typeof (v as any).label === "string" && (v as any).label.trim() !== ""
&& Object.prototype.hasOwnProperty.call(v, "grading");
} Try / catch
try {
const cells = parseGradesFile(path);
} catch (err) {
// Surface the message verbatim — it already names the offending entry.
console.error(String((err as Error).message));
process.exit(1);
} Prevention
- Lint grades.json with a JSON Schema requiring both label and grading on every array item.
- Use isGradeEntry as a row-level filter in a script that generates the file.
- Run `hyperframes grade-compare --help` to re-confirm the { label, grading } contract after upgrades.
When it happens
Trigger: Running `hyperframes grade-compare --grades grades.json` where at least one array element looks like `{"label":"Warm"}` (no `grading` key). Also triggered by programmatic callers of the exported parseGradesFile with the same malformed input.
Common situations: Hand-authoring a grades JSON and forgetting the field; renaming `grading` to `grade`/`look`/`preset`; schema drift after a HyperFrames upgrade that renamed the key; copy-pasting a partial object.
Related errors
- At least one grade candidate is required
- --luts must include at least one LUT path
- --for <path> is required
- Exactly one of --grades or --luts is required
- At least one grade cell is required
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/3e9980f4b5c8831c.
Report an issue: GitHub.