{"record":{"id":"93a52176a649d193","repo":"heygen-com/hyperframes","slug":"grades-file-must-be-a-json-array-of-label-gradi","errorCode":null,"errorMessage":"Grades file must be a JSON array of { label, grading } objects","messagePattern":"Grades file must be a JSON array of (.+?) objects","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/grade-compare.ts","lineNumber":221,"sourceCode":"    next.lut = nextLut;\n  }\n  return next;\n}\n\nexport function parseGradesFile(filePath: string): GradeCompareCell[] {\n  if (!existsSync(filePath)) {\n    throw new Error(`Grades file not found: ${filePath}`);\n  }\n\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[] {","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/grade-compare.ts#L203-L239","documentation":"Thrown by parseGradesFile() after a successful JSON.parse: the top-level value must be an array (Array.isArray). Each element becomes one grade cell, so a bare object or scalar is rejected. The message states the expected element shape { label, grading }.","triggerScenarios":"Top-level is an object wrapper like { \"cells\": [...] }; a single grade object instead of a one-element array; top-level is a number/string/boolean.","commonSituations":"Wrapping the array in a container object for documentation purposes; exporting a single preset as an object from another tool; a schema mismatch.","solutions":["Make the top-level value a JSON array","Move any wrapper object's contents out to the array root","Confirm with `JSON.parse` + `Array.isArray` in a quick script"],"exampleFix":"// before\n{\n  \"cells\": [\n    { \"label\": \"warm\", \"grading\": {} }\n  ]\n}\n// after\n[\n  { \"label\": \"warm\", \"grading\": {} }\n]","handlingStrategy":"type-guard","validationCode":"if (!Array.isArray(parsed)) {\n  throw new Error('grades file top-level must be a JSON array of { label, grading } objects');\n}","typeGuard":"function isGradesArray(parsed: unknown): parsed is unknown[] {\n  return Array.isArray(parsed);\n}","tryCatchPattern":null,"preventionTips":["Make the top-level value a JSON array","Do not wrap the array in a container object","Quick-check with JSON.parse followed by Array.isArray in a scratch script"],"tags":["grade-compare","json","type-guard","validation"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}