pbakaus/impeccable · error · Error

payload needs an options array

Error message

payload needs an options array

What it means

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.

Source

Thrown at plugin/skills/impeccable/scripts/serve-question.mjs:341

else raw = fs.readFileSync(0, 'utf8');

// Round state is mutable: a re-roll keeps this server alive and --update
// swaps in the next hand, so payload, options, and the local-image table
// rebuild per round.
let payload;
let options;
let localImages = [];
// Build path (comp-led vs code-led): the payload carries the recorded
// default; the page's toggle updates the live value per session. The server
// owns both so the final ANSWER states the path and whether it was flipped
// even when the round never rendered a toggle.
let buildPathDefault = null;
let liveBuildPath = null;

function loadRound(json) {
  const parsed = JSON.parse(json);
  if (!parsed || !Array.isArray(parsed.options) || parsed.options.length === 0) {
    throw new Error('payload needs an options array');
  }
  localImages = [];
  const imageSrc = (value) => {
    if (!value) return null;
    if (/^https?:\/\//.test(value)) return value;
    const abs = path.resolve(value);
    if (!fs.existsSync(abs)) return null;
    localImages.push(abs);
    return `/img/${localImages.length - 1}`;
  };
  // Comps stream in after the page is served, so their slots register
  // whether or not the file exists yet; /img answers 404 until it lands and
  // the page polls the slot. Remote comp URLs pass through untouched.
  const compSrc = (value) => {
    if (!value) return null;
    if (/^https?:\/\//.test(value)) return value;
    localImages.push(path.resolve(value));
    return `/img/${localImages.length - 1}`;

View on GitHub (pinned to d14711ae3d)

Solutions

  1. Ensure the payload JSON has a non-empty `options` array, e.g. { "options": [{ "id": "a", ... }] }.
  2. Validate the payload with the schema before piping it to serve-question.
  3. If the round has no contenders yet, generate them first rather than serving an empty options list.

Example fix

// before
{ "prompt": "redesign", "options": [] }

// after
{ "prompt": "redesign", "options": [{ "id": "a", "hero": "./a.png" }] }
Defensive patterns

Strategy: validation

Validate before calling

function hasNonEmptyOptions(payload) {
  return Array.isArray(payload?.options) && payload.options.length > 0;
}

Type guard

function isServeQuestionPayload(value) {
  return value !== null && typeof value === 'object' && Array.isArray(value.options) && value.options.length > 0;
}

Try / catch

let parsed;
try {
  parsed = JSON.parse(raw);
} catch (err) {
  throw new Error('payload is not valid JSON: ' + err.message);
}
if (!isServeQuestionPayload(parsed)) {
  throw new Error('payload missing non-empty options array');
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13). Data as JSON: /api/errors/ec36a66df380d965. Report an issue: GitHub.