Yeachan-Heo/oh-my-codex · error
answers[${index}].answer must include selected_labels[] and
Error message
answers[${index}].answer must include selected_labels[] and selected_values[] What it means
Thrown by normalizeSubmittedAnswers after kind validation passes. Every submitted answer must carry selected_labels and selected_values as actual arrays, since the renderer and result aggregation iterate both. If either is missing or not an array (e.g. a string or object), this error is raised with the offending index.
Source
Thrown at src/question/events.ts:228
if (rawAnswers.length === 0) throw new Error('answer payload must include answer or answers[]');
const validQuestionIds = new Set((record.questions ?? []).map((question) => question.id));
if (validQuestionIds.size === 0) validQuestionIds.add('q-1');
const seen = new Set<string>();
return rawAnswers.map((entry, index) => {
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) throw new Error(`answers[${index}] must be an object`);
const object = entry as Record<string, unknown>;
const questionId = safeString(object.question_id) || (record.questions?.[index]?.id ?? (index === 0 ? 'q-1' : ''));
if (!questionId || !validQuestionIds.has(questionId)) throw new Error(`answers[${index}].question_id is unknown for this question: ${questionId || '<missing>'}`);
if (seen.has(questionId)) throw new Error(`answers question_id must be unique: ${questionId}`);
seen.add(questionId);
const answer = object.answer;
if (!answer || typeof answer !== 'object' || Array.isArray(answer)) throw new Error(`answers[${index}].answer must be an object`);
const answerObject = answer as Record<string, unknown>;
const kind = safeString(answerObject.kind);
if (!['option', 'other', 'multi'].includes(kind)) throw new Error(`answers[${index}].answer.kind must be option, other, or multi`);
if (!Array.isArray(answerObject.selected_labels) || !Array.isArray(answerObject.selected_values)) {
throw new Error(`answers[${index}].answer must include selected_labels[] and selected_values[]`);
}
return {
question_id: questionId,
index: Number.isInteger(object.index) ? object.index as number : index,
answer: answerObject as unknown as QuestionAnswerEntry['answer'],
};
});
}
View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Add both arrays: selected_labels: string[] and selected_values: string[].
- Wrap scalar selections in arrays (selected_values: ['yes'], not selected_values: 'yes').
- Run normalizeSubmittedAnswers on a sample payload during development to catch shape drift early.
Example fix
// before
answer: { kind: 'option', selected_values: 'yes' }
// after
answer: { kind: 'option', selected_labels: ['Yes'], selected_values: ['yes'] } Defensive patterns
Strategy: validation
Validate before calling
const ok = answers.every((e, i) => Array.isArray(e?.answer?.selected_labels) && Array.isArray(e?.answer?.selected_values) );
Type guard
function hasSelectionArrays(a: unknown): a is { selected_labels: string[]; selected_values: string[] } {
const o = a as Record<string, unknown>;
return Array.isArray(o?.selected_labels) && Array.isArray(o?.selected_values);
} Try / catch
try { await result({ answers }); } catch (e) { if (e instanceof Error && /selected_labels\[\] and selected_values\[\]/.test(e.message)) { /* backfill missing arrays */ } else throw e; } Prevention
- Always wrap selections in arrays, even single-select (one-element arrays).
- Add a zod schema: z.object({ kind: z.enum(['option','other','multi']), selected_labels: z.array(z.string()), selected_values: z.array(z.string()) }).
- Assert payload shape in tests before submitting.
When it happens
Trigger: Submitting answers[i].answer with kind 'option'/'other'/'multi' but omitting selected_labels or selected_values, or sending them as strings/objects (e.g. selected_labels: 'Yes' instead of ['Yes']).
Common situations: Minimal hand-written payloads that only include a value; clients that model single-select as a scalar instead of a one-element array; copying example JSON that predates the two-array schema.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- answers[${index}].answer.kind must be option, other, or mult
- ${path} must be a non-empty string array
- selected value is not in the option schema: ${value}
- ${path} cardinality must match selected values
- ${path}[${mismatchIndex}] must match the selected value labe
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/fd7a61b33f06a96f.
Report an issue: GitHub.