{"record":{"id":"ec36a66df380d965","repo":"pbakaus/impeccable","slug":"payload-needs-an-options-array","errorCode":null,"errorMessage":"payload needs an options array","messagePattern":"payload needs an options array","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugin/skills/impeccable/scripts/serve-question.mjs","lineNumber":341,"sourceCode":"else raw = fs.readFileSync(0, 'utf8');\n\n// Round state is mutable: a re-roll keeps this server alive and --update\n// swaps in the next hand, so payload, options, and the local-image table\n// rebuild per round.\nlet payload;\nlet options;\nlet localImages = [];\n// Build path (comp-led vs code-led): the payload carries the recorded\n// default; the page's toggle updates the live value per session. The server\n// owns both so the final ANSWER states the path and whether it was flipped\n// even when the round never rendered a toggle.\nlet buildPathDefault = null;\nlet liveBuildPath = null;\n\nfunction loadRound(json) {\n  const parsed = JSON.parse(json);\n  if (!parsed || !Array.isArray(parsed.options) || parsed.options.length === 0) {\n    throw new Error('payload needs an options array');\n  }\n  localImages = [];\n  const imageSrc = (value) => {\n    if (!value) return null;\n    if (/^https?:\\/\\//.test(value)) return value;\n    const abs = path.resolve(value);\n    if (!fs.existsSync(abs)) return null;\n    localImages.push(abs);\n    return `/img/${localImages.length - 1}`;\n  };\n  // Comps stream in after the page is served, so their slots register\n  // whether or not the file exists yet; /img answers 404 until it lands and\n  // the page polls the slot. Remote comp URLs pass through untouched.\n  const compSrc = (value) => {\n    if (!value) return null;\n    if (/^https?:\\/\\//.test(value)) return value;\n    localImages.push(path.resolve(value));\n    return `/img/${localImages.length - 1}`;","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/pbakaus/impeccable/blob/d14711ae3d1a1dd62dee61a358d27f107c51ccd0/plugin/skills/impeccable/scripts/serve-question.mjs#L323-L359","documentation":"Thrown by loadRound in serve-question.mjs when the parsed payload is falsy, has no options array, or the options array is empty. The serve-question page renders option cards, so a payload with zero options cannot produce a meaningful round.","triggerScenarios":"Invoking serve-question with a payload file (or stdin) whose JSON is an object without an `options` key, where options is not an array, or where the array is empty.","commonSituations":"Payload schema changed between the generator and the server, an empty/placeholder payload was fed in, or a JSON file missing the options field entirely.","solutions":["Ensure the payload JSON has a non-empty `options` array, e.g. { \"options\": [{ \"id\": \"a\", ... }] }.","Validate the payload with the schema before piping it to serve-question.","If the round has no contenders yet, generate them first rather than serving an empty options list."],"exampleFix":"// before\n{ \"prompt\": \"redesign\", \"options\": [] }\n\n// after\n{ \"prompt\": \"redesign\", \"options\": [{ \"id\": \"a\", \"hero\": \"./a.png\" }] }","handlingStrategy":"validation","validationCode":"function hasNonEmptyOptions(payload) {\n  return Array.isArray(payload?.options) && payload.options.length > 0;\n}","typeGuard":"function isServeQuestionPayload(value) {\n  return value !== null && typeof value === 'object' && Array.isArray(value.options) && value.options.length > 0;\n}","tryCatchPattern":"let parsed;\ntry {\n  parsed = JSON.parse(raw);\n} catch (err) {\n  throw new Error('payload is not valid JSON: ' + err.message);\n}\nif (!isServeQuestionPayload(parsed)) {\n  throw new Error('payload missing non-empty options array');\n}","preventionTips":["Validate payloads against a JSON schema before piping to serve-question.","Unit-test the generator's output shape against isServeQuestionPayload.","Fail fast in the generator when no options are produced instead of emitting an empty list."],"tags":["json","validation","serve-question","payload"],"backgroundTag":null,"analyzedSha":"d14711ae3d1a1dd62dee61a358d27f107c51ccd0","analyzedAt":"2026-08-13T00:52:25.771Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}