Yeachan-Heo/oh-my-codex · error · Error

Structured question returned an invalid next-step answer.

Error message

Structured question returned an invalid next-step answer.

What it means

After extracting a structured answer for the next-step prompt, promptAction() only accepts the lowercased values 'launch' or 'refine'. Any other string (or non-string answer.value) is invalid and throws before falling back to interactive input.

Solutions

  1. Make the structured asker return exactly 'launch' or 'refine' as answer.value
  2. If the answerer is an LLM prompt, constrain it (enum/single-choice) so it emits only those two tokens
  3. Catch this error and fall back to interactive io.question (shouldFallbackFromStructuredQuestion-style logic)

Example fix

// before
answer: { value: 'launch when ready' }
// after
answer: { value: 'launch' }
Defensive patterns

Strategy: fallback

Validate before calling

const val = String(answer?.value ?? '').trim().toLowerCase();
if (val !== 'launch' && val !== 'refine') {
  // fall back to interactive prompt instead of throwing
  return await io.question('Next step [launch/refine further]\n> ');
}

Type guard

const isValidAction = (v: unknown): v is 'launch'|'refine' =>
  typeof v === 'string' && ['launch','refine'].includes(v.trim().toLowerCase());

Try / catch

try { return await promptActionStructured(resp); } catch (e) { if (e.message.includes('invalid next-step answer')) return await promptActionInteractive(io); throw e; }

Prevention

When it happens

Trigger: The structured asker returns an answer whose trimmed/lowercased value is something else — e.g. 'launch!', 'yes', 'L', or answer.value being a number/object (typeof !== 'string' yields '').

Common situations: LLM-backed answerers returning free-form text like 'let us launch now', multi-select payloads, or non-string value types from a changed schema.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/927966bedda3bebf. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/autoresearch-guided.ts:142

					value: "launch",
					description: "Finalize artifacts and hand off to $autoresearch.",
				},
				{
					label: "Refine further",
					value: "refine",
					description: "Keep clarifying before launch.",
				},
			],
			allow_other: false,
			source: "deep-interview",
		});
		const answer = primaryStructuredAnswer(response);
		const answerValue = typeof answer.value === "string"
			? answer.value.trim().toLowerCase()
			: "";
		if (answerValue === "launch") return "launch";
		if (answerValue === "refine") return "refine";
		throw new Error('Structured question returned an invalid next-step answer.');
	}

	const answer = (
		await io.question(
			`\nNext step [launch/refine further] (default: ${launchReady ? "launch" : "refine further"})\n> `,
		)
	)
		.trim()
		.toLowerCase();
	if (!answer) return launchReady ? "launch" : "refine";
	if (answer === "launch") return "launch";
	if (answer === "refine further" || answer === "refine" || answer === "r")
		return "refine";
	throw new Error('Please choose either "launch" or "refine further".');
}

function createStructuredQuestionAsker(
	repoRoot: string,

View on GitHub (pinned to 3ad79a8a6f)