{"record":{"id":"5e76a2c836623977","repo":"heygen-com/hyperframes","slug":"lut-data-rows-must-contain-three-numbers","errorCode":null,"errorMessage":"LUT data rows must contain three numbers","messagePattern":"LUT data rows must contain three numbers","errorType":"validation","errorClass":"CubeLutParseError","httpStatus":null,"severity":"error","filePath":"packages/core/src/colorLuts.ts","lineNumber":163,"sourceCode":"        throw new CubeLutParseError(`LUT_3D_SIZE ${lut3dSize} exceeds max ${maxSize}`, lineNumber);\n      }\n      continue;\n    }\n\n    if (!isNumericDataLine(keyword)) {\n      if (keyword.startsWith(\"LUT_\")) {\n        throw new CubeLutParseError(`Unsupported cube keyword ${keyword}`, lineNumber);\n      }\n      continue;\n    }\n    if (!lut3dSize) {\n      if (lut1dSize) {\n        throw new CubeLutParseError(\"1D cube LUTs are not supported yet\", lineNumber);\n      }\n      throw new CubeLutParseError(\"LUT data appears before LUT_3D_SIZE\", lineNumber);\n    }\n    if (parts.length !== 3) {\n      throw new CubeLutParseError(\"LUT data rows must contain three numbers\", lineNumber);\n    }\n    rows.push(\n      parseFiniteNumber(parts[0]!, lineNumber),\n      parseFiniteNumber(parts[1]!, lineNumber),\n      parseFiniteNumber(parts[2]!, lineNumber),\n    );\n  }\n\n  if (lut1dSize && lut3dSize) {\n    throw new CubeLutParseError(\"Mixed 1D and 3D cube LUTs are not supported yet\");\n  }\n  if (!lut3dSize) {\n    if (lut1dSize) throw new CubeLutParseError(\"1D cube LUTs are not supported yet\");\n    throw new CubeLutParseError(\"Missing LUT_3D_SIZE\");\n  }\n  validateDomain(domainMin, domainMax);\n\n  const expectedRows = lut3dSize * lut3dSize * lut3dSize;","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/core/src/colorLuts.ts#L145-L181","documentation":"Each 3D LUT data row must carry exactly three numeric tokens (R, G, B). The throw at line 163 fires when a numeric data line splits into a token count other than three. It runs after LUT_3D_SIZE is known, so it only applies to genuine data rows.","triggerScenarios":"A row like '0.1 0.2' (two channels), '0.1 0.2 0.3 0.4' (four — e.g. RGBA), or a row where a stray whitespace token inflated the count.","commonSituations":"RGBA exports from a tool that appends alpha; a missing channel from a truncated row; an extra blank-ish token (tab sequences) producing an empty string in the split.","solutions":["Ensure every data row has exactly three numeric values separated by whitespace.","If the source is RGBA, drop the fourth column before parsing.","Normalize repeated whitespace (e.g. text.replace(/\\s+/g, ' ')) and re-check."],"exampleFix":"// before\n0.10 0.20 0.30 1.00\n\n// after\n0.10 0.20 0.30","handlingStrategy":"try-catch","validationCode":"function assertDataRowsAreTriples(fileText: string): void {\n  for (const line of fileText.split(/\\r?\\n/)) {\n    const tok = line.trim().split(/\\s+/)[0] ?? '';\n    if (/^[+-]?(?:\\d|\\.\\d)/.test(tok) && line.trim().split(/\\s+/).length !== 3) {\n      throw new Error('Each data row must have exactly three numbers');\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  parseCubeLut(fileText);\n} catch (err) {\n  if (err instanceof CubeLutParseError && /must contain three numbers/.test(err.message)) {\n    // report err.lineNumber; if RGBA, strip the 4th column and retry\n  } else throw err;\n}","preventionTips":["Export RGB (3 channels), not RGBA, from the source tool.","Normalize repeated whitespace before parsing.","Validate row arity in a pre-scan when ingesting untrusted LUTs."],"tags":["lut","cube","parsing","data"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}