{"record":{"id":"db9eaefda8f7421b","repo":"Yeachan-Heo/oh-my-codex","slug":"structured-question-returned-no-answer","errorCode":null,"errorMessage":"Structured question returned no answer.","messagePattern":"Structured question returned no answer\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/autoresearch-guided.ts","lineNumber":59,"sourceCode":"\nexport interface AutoresearchStructuredQuestionInput {\n\theader?: string;\n\tquestion: string;\n\toptions: Array<{ label: string; value: string; description?: string }>;\n\tallow_other: boolean;\n\tother_label?: string;\n\tmulti_select?: boolean;\n\ttype?: QuestionType;\n\tsource?: string;\n}\n\nexport type AutoresearchStructuredQuestionAsker = (\n\tinput: AutoresearchStructuredQuestionInput,\n) => Promise<OmxQuestionSuccessPayload>;\n\nfunction primaryStructuredAnswer(response: OmxQuestionSuccessPayload): OmxQuestionSuccessPayload[\"answers\"][number][\"answer\"] {\n\tconst answer = response.answers[0]?.answer ?? response.answer;\n\tif (!answer) throw new Error(\"Structured question returned no answer.\");\n\treturn answer;\n}\n\nfunction createQuestionIO(): AutoresearchQuestionIO {\n\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\n\treturn {\n\t\tquestion(prompt: string) {\n\t\t\treturn rl.question(prompt);\n\t\t},\n\t\tclose() {\n\t\t\trl.close();\n\t\t},\n\t};\n}\n\nasync function promptWithDefault(\n\tio: AutoresearchQuestionIO,\n\tprompt: string,","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/autoresearch-guided.ts#L41-L77","documentation":"primaryStructuredAnswer() extracts the answer from a structured question response by reading response.answers[0].answer, falling back to response.answer. If both are missing/empty, the guided autoresearch flow cannot proceed and throws.","triggerScenarios":"A structured question asker (the OMX question API invoked with createStructuredQuestionAsker) returns a success payload whose answers array is empty and which has no top-level answer field — e.g. a respondent skipped the question or a stub/mock asker returned an empty success object.","commonSituations":"Non-interactive contexts where the question backend returns an empty payload, mocks in tests returning {answers: []}, or upstream format changes where the answer lives under a different key.","solutions":["Inspect the OmxQuestionSuccessPayload returned by the asker to see where the answer actually lives (answers[0].answer vs answer)","If using a custom asker/mock, ensure it returns at least one entry in answers with a non-empty answer field","In non-interactive automation, provide the answer directly instead of relying on the structured question path","Wrap calls in try-catch and fall back to the plain readline io.question path"],"exampleFix":"// before\nconst asker = async () => ({ answers: [] });\n// after\nconst asker = async () => ({ answers: [{ id: 'q1', answer: { value: 'launch' } }] });","handlingStrategy":"type-guard","validationCode":"const resp = await asker(input);\nif (!resp.answers?.[0]?.answer && !resp.answer) {\n  throw new RetryableError('question backend returned no answer; retry or use interactive path');\n}","typeGuard":"function hasStructuredAnswer(r: OmxQuestionSuccessPayload): boolean {\n  return Boolean(r.answers?.[0]?.answer ?? r.answer);\n}","tryCatchPattern":"try { return primaryStructuredAnswer(resp); } catch (e) { if (e.message === 'Structured question returned no answer.') return await io.question(promptText); throw e; }","preventionTips":["Validate asker responses in tests with fixture payloads containing answers","Prefer constrained single-question prompts"],"tags":["structured-question","empty-response","autoresearch"],"backgroundTag":"empty-api-response","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}