Yeachan-Heo/oh-my-codex · error · Error
question input must be a JSON object
Error message
question input must be a JSON object
What it means
normalizeQuestionInput requires the top-level question input to be a plain JSON object. Arrays, strings, numbers, null, or primitives are rejected because the normalizer expects an object with fields like header, source, questions, etc.
Source
Thrown at src/question/types.ts:185
return {
id,
...(header ? { header } : {}),
question,
options: rawOptions.map((option, optionIndex) => normalizeOption(option, optionIndex)),
allow_other,
other_label,
multi_select: type === 'multi-answerable',
type,
};
}
function normalizeLegacyQuestion(raw: Record<string, unknown>, header?: string): NormalizedQuestionItem {
return normalizeQuestionItem({ ...raw, id: safeString(raw.id).trim() || 'q-1', header }, 0, header);
}
export function normalizeQuestionInput(raw: unknown): QuestionInput {
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
throw new Error('question input must be a JSON object');
}
const input = raw as Record<string, unknown>;
const header = safeString(input.header).trim() || undefined;
const source = safeString(input.source).trim() || undefined;
const session_id = safeString(input.session_id).trim() || undefined;
const rawQuestions = Array.isArray(input.questions) ? input.questions : undefined;
const questions = rawQuestions
? rawQuestions.map((item, index) => normalizeQuestionItem(item, index, header))
: [normalizeLegacyQuestion(input, header)];
if (questions.length === 0) throw new Error('questions must be a non-empty array');
const seenIds = new Set<string>();
for (const question of questions) {
if (seenIds.has(question.id)) throw new Error(`questions id must be unique: ${question.id}`);
seenIds.add(question.id);
}View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Wrap arrays in an object: { questions: [...] } instead of a bare array
- Ensure you JSON.parse the payload before passing it
- Check the value is non-null and typeof === 'object' before calling
Example fix
// before
normalizeQuestionInput([{ id: 'q1' }]);
// after
normalizeQuestionInput({ questions: [{ id: 'q1' }] }); Defensive patterns
Strategy: type-guard
Validate before calling
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new TypeError('expected a question object'); Type guard
const isQuestionObject = (v: unknown): v is Record<string, unknown> => Boolean(v) && typeof v === 'object' && !Array.isArray(v);
Prevention
- Always JSON.parse before passing
- Wrap arrays as { questions: [...] }
When it happens
Trigger: Calling normalizeQuestionInput (or an API that normalizes input, e.g. record builders) with a JSON array of questions, a JSON string, or a null/undefined value.
Common situations: Passing JSON.parse output that is an array of question objects; reading a file whose root is an array; passing a stringified JSON instead of a parsed object.
Related errors
- questions must be a non-empty array
- Invalid autoresearch-goal mission at ${repoRelative(cwd, pat
- autoresearch candidate artifact must be valid JSON
- autoresearch candidate artifact must be a JSON object
- autoresearch candidate artifact notes must be a string array
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/dc2b3eac9c775da2.
Report an issue: GitHub.