{"record":{"id":"a92e68d63672b368","repo":"heygen-com/hyperframes","slug":"luts-must-include-at-least-one-lut-path","errorCode":null,"errorMessage":"--luts must include at least one LUT path","messagePattern":"--luts must include at least one LUT path","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/grade-compare.ts","lineNumber":245,"sourceCode":"    }\n    const label = entry.label;\n    if (typeof label !== \"string\" || !label.trim()) {\n      throw new Error(`Grade entry ${index + 1} must have a non-empty string label`);\n    }\n    if (!hasOwn(entry, \"grading\")) {\n      throw new Error(`Grade entry \"${label}\" must include a grading value`);\n    }\n    return validateCell(label, entry.grading);\n  });\n}\n\nexport function resolveLutCells(luts: string): GradeCompareCell[] {\n  const paths = luts\n    .split(\",\")\n    .map((part) => part.trim())\n    .filter(Boolean);\n  if (paths.length === 0) {\n    throw new Error(\"--luts must include at least one LUT path\");\n  }\n  return paths.map((lutPath) =>\n    validateCell(basename(lutPath, extname(lutPath)), { lut: { src: lutPath } }),\n  );\n}\n\n// The ungraded frame as a leading reference cell. An empty grading object\n// normalizes to inactive, so the runtime renders the source image untouched —\n// giving the agent a baseline to judge every candidate look against.\nexport function prependBaselineCell(cells: GradeCompareCell[]): GradeCompareCell[] {\n  return [validateCell(\"original\", {}), ...cells];\n}\n\nexport function parseGradeCompareArgs(args: {\n  for?: unknown;\n  grades?: unknown;\n  luts?: unknown;\n  project?: unknown;","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/grade-compare.ts#L227-L263","documentation":"Thrown by resolveLutCells when the `--luts` argument, after splitting on commas and trimming, yields zero non-empty paths. The flag is declared optional at the citty layer, so an empty or all-whitespace value reaches this function and is rejected here rather than rendering an empty sheet.","triggerScenarios":"Passing `--luts \"\"`, `--luts \",,\"`, or `--luts \"   \"` to `hyperframes grade-compare`. Also hit by a direct call `resolveLutCells(\"\")` or `resolveLutCells(\",,\")`.","commonSituations":"Shell quoting that swallows the value (e.g. an unset env var inside the quoted string); a script templating `--luts ${LUTS}` where LUTS is empty; trailing-comma typos.","solutions":["Supply at least one real .cube path: `--luts looks/a.cube,looks/b.cube`.","If the value comes from a variable, guard it in the shell first: `[ -n \"$LUTS\" ] && hyperframes grade-compare --for f.png --luts \"$LUTS\"`.","Switch to `--grades grades.json` if you want to define looks inline rather than as file paths."],"exampleFix":"# before\nhyperframes grade-compare --for frame.png --luts \"\"\n# after\nhyperframes grade-compare --for frame.png --luts looks/warm.cube,looks/cool.cube","handlingStrategy":"validation","validationCode":"// Validate a --luts string before passing it\ndefineLutsArg(raw: string): string[] {\n  const paths = raw.split(\",\").map((p) => p.trim()).filter(Boolean);\n  if (paths.length === 0) throw new Error(\"--luts needs at least one .cube path\");\n  return paths;\n}","typeGuard":"function isNonEmptyLutList(s: string): boolean {\n  return s.split(\",\").map((p) => p.trim()).filter(Boolean).length > 0;\n}","tryCatchPattern":"try {\n  const cells = resolveLutCells(lutsArg);\n} catch (err) {\n  console.error((err as Error).message); // already actionable\n  process.exit(1);\n}","preventionTips":["Construct the --luts value from a non-empty array of paths joined by commas.","In shell, guard empty variables before invoking: `[ -n \"$LUTS\" ] || exit 1`.","Prefer --grades grades.json when looks are defined inline to avoid path-list string building."],"tags":["cli","input-validation","luts","grade-compare","shell"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}