heygen-com/hyperframes · error · Error
At least one grade candidate is required
Error message
At least one grade candidate is required
What it means
Thrown by the grade-compare command's run() after parsing grades/luts and getting back an empty cells array. This is distinct from the lower-level buildGradeCompareHtml guard (error 144): it fires at the command layer, after parseGradesFile or resolveLutCells returned `[]`. In practice parseGradesFile cannot return empty (a JSON `[]` array passes the Array.isArray check and the map yields nothing), and resolveLutCells rejects empty input — so this is the guard that catches an empty `[]` grades file.
Source
Thrown at packages/cli/src/commands/grade-compare.ts:638
async run({ args }) {
const jsonRequested = args.json === true;
let preparedDir: string | null = null;
try {
const parsed = parseGradeCompareArgs({
for: args.for,
grades: args.grades,
luts: args.luts,
project: args.project,
out: args.out,
json: args.json,
timeout: args.timeout,
});
let cells =
parsed.source.kind === "grades"
? parseGradesFile(parsed.source.path)
: resolveLutCells(parsed.source.value);
if (cells.length === 0) {
throw new Error("At least one grade candidate is required");
}
const capResult = capCandidateCells(cells);
cells = capResult.cells;
warnInactiveGradingCells(cells);
if (args.baseline !== false) {
cells = prependBaselineCell(cells);
}
if (!parsed.json) {
console.log(
`${c.accent("◆")} Rendering ${cells.length} grade candidates from ${c.accent(basename(parsed.framePath))}`,
);
}
const frame = await loadReferenceFrame(parsed.framePath);
const prepared = await prepareGradeCompareTempProject({
projectDir: parsed.projectDir,
framePath: parsed.framePath,View on GitHub (pinned to c2996c8626)
Solutions
- Add at least one `{ label, grading }` entry to grades.json.
- If a script generates the file, ensure it errors upstream when it would emit zero candidates rather than writing `[]`.
- Switch to `--luts` with at least one .cube path if you have no inline grades to define.
Example fix
// before — grades.json
[]
// after
[{"label":"Warm","grading":{"temperature":0.2}}] Defensive patterns
Strategy: validation
Validate before calling
// Reject an empty grades array before invoking grade-compare
import { readFileSync } from "node:fs";
function assertNonEmptyGrades(path: string): void {
const parsed = JSON.parse(readFileSync(path, "utf-8"));
if (!Array.isArray(parsed) || parsed.length === 0) {
throw new Error("grades file must be a non-empty array");
}
} Type guard
function isNonEmptyArray(v: unknown): v is unknown[] {
return Array.isArray(v) && v.length > 0;
} Try / catch
try {
// run grade-compare
} catch (err) {
if (/At least one grade candidate/.test((err as Error).message))) {
// add an entry to grades.json or switch to --luts
}
} Prevention
- Make any script that generates grades.json fail loudly when it would emit zero candidates.
- Use isNonEmptyArray on the parsed file in a pre-flight check.
- Prefer --luts for quick one-off comparisons to avoid empty-manifest edge cases.
When it happens
Trigger: Supplying `--grades grades.json` where grades.json is exactly `[]` (a valid JSON array with zero entries). The file parses, passes the array check, the map produces no cells, and this guard rejects it.
Common situations: A grades JSON templated/generated by a script that emitted an empty array when no looks matched a filter; hand-editing that stripped all entries; a CI step producing an empty manifest.
Related errors
- Grade entry "${label}" must include a grading value
- --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/64fb28e08692a360.
Report an issue: GitHub.