{"record":{"id":"ba9b1ebac604ae0e","repo":"heygen-com/hyperframes","slug":"grade-entry-index-1-must-have-a-non-empty-str","errorCode":null,"errorMessage":"Grade entry ${index + 1} must have a non-empty string label","messagePattern":"Grade entry (.+?) must have a non-empty string label","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/grade-compare.ts","lineNumber":230,"sourceCode":"\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(readFileSync(filePath, \"utf-8\"));\n  } catch (err) {\n    throw new Error(`Could not parse grades JSON: ${normalizeErrorMessage(err)}`);\n  }\n\n  if (!Array.isArray(parsed)) {\n    throw new Error(\"Grades file must be a JSON array of { label, grading } objects\");\n  }\n\n  return parsed.map((entry, index) => {\n    if (!isRecord(entry)) {\n      throw new Error(`Grade entry ${index + 1} must be an object with label and grading`);\n    }\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 } }),","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/grade-compare.ts#L212-L248","documentation":"Thrown by parseGradesFile() when an entry passes isRecord but its label is not a non-empty string: typeof label !== 'string' (missing, null, number) or label.trim() is empty (\"\" or whitespace-only). The label drives both the cell caption and the LUT-rewrite lookup, so it must be a real string.","triggerScenarios":"entry.label omitted entirely; label: null or a number; label: \"\" or \"   \"; using a different key like \"name\" instead of \"label\".","commonSituations":"Using \"name\" instead of the required \"label\" key; an empty label from a template; whitespace from copy-paste.","solutions":["Add a non-empty string `label` to every entry","Use the exact key name 'label' (not 'name' or 'title')","Trim the value so it is not only whitespace"],"exampleFix":"// before\n[\n  { \"name\": \"warm\", \"grading\": {} }\n]\n// after\n[\n  { \"label\": \"warm\", \"grading\": {} }\n]","handlingStrategy":"type-guard","validationCode":"if (typeof entry.label !== 'string' || entry.label.trim().length === 0) {\n  throw new Error(`entry ${index + 1} needs a non-empty string label`);\n}","typeGuard":"function hasNonEmptyLabel(entry: unknown): entry is { label: string } {\n  return typeof (entry as { label?: unknown })?.label === 'string' &&\n    ((entry as { label: string }).label.trim().length > 0);\n}","tryCatchPattern":null,"preventionTips":["Use the exact key 'label' (not 'name' or 'title')","Ensure the label is a non-empty, non-whitespace string","Trim labels at the source so whitespace-only values never reach the parser"],"tags":["grade-compare","json","type-guard","validation","label"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}