can1357/oh-my-pi · error · Error

Ask question index exceeded the requested question list

Error message

Ask question index exceeded the requested question list

What it means

A defensive internal invariant in the multi-question loop: resultsByIndex is pre-sized to params.questions.length, so params.questions[questionIndex] should always exist while the loop condition holds. If the array somehow contains a hole (sparse array) or was mutated during iteration, this plain Error is thrown rather than dereferencing undefined.

Source

Thrown at packages/coding-agent/src/tools/ask.ts:1055

				timedOut: timedOut || undefined,
			};

			const responseText = formatSingleQuestionResponse({
				selectedOptions,
				customInput,
				note,
				timedOut: timedOut || undefined,
				multi: q.multi ?? false,
			});

			return { content: [{ type: "text" as const, text: responseText }], details };
		}

		const resultsByIndex: Array<QuestionResult | undefined> = Array.from({ length: params.questions.length });
		let questionIndex = 0;
		while (questionIndex < params.questions.length) {
			const q = params.questions[questionIndex];
			if (!q) throw new Error("Ask question index exceeded the requested question list");
			const previous = resultsByIndex[questionIndex];
			const navigation: NavigationControls = {
				allowBack: questionIndex > 0,
				allowForward: true,
				progressText: `${questionIndex + 1}/${params.questions.length}`,
			};
			const {
				optionLabels,
				selectedOptions,
				customInput,
				note,
				navigation: navAction,
				cancelled,
				timedOut,
			} = await askQuestion(q, { previous, navigation });

			if (cancelled && !timedOut) {
				context.abort();

View on GitHub (pinned to 9690622007)

Solutions

  1. Ensure the questions array is dense: contiguous indices 0..length-1 with a Question at each.
  2. Construct with literal/array methods (map, filter with type narrowing) instead of index assignment on an empty array.
  3. Filter out holes before calling: `questions.filter(Boolean)` then verify length matches expected.

Example fix

// before (sparse)
const questions = [];
questions[0] = q1;
questions[2] = q3; // hole at index 1
// after
const questions = [q1, q3]; // dense array
Defensive patterns

Strategy: validation

Validate before calling

function assertDenseQuestions(questions: Question[]): Question[] {
  if (!Array.isArray(questions)) throw new TypeError('questions must be an array');
  if (questions.filter(Boolean).length !== questions.length) {
    throw new TypeError('questions contains holes/undefined entries');
  }
  return questions;
}

Type guard

function hasNoHoles<T>(arr: T[]): boolean {
  return arr.length === arr.filter(() => true).length && arr.every(x => x !== undefined && x !== null);
}

Prevention

When it happens

Trigger: Passing a sparse array as questions (e.g. `const qs = []; qs[2] = {...}`) or an array-like whose length exceeds actual elements; mutation of the questions array during the tool run.

Common situations: Programmatic/SDK callers building the questions array dynamically and leaving gaps; deserialization code that reconstructs a sparse array from a JSON map keyed by index.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/30ecb1b8124503ad. Report an issue: GitHub.