{"record":{"id":"30ecb1b8124503ad","repo":"can1357/oh-my-pi","slug":"ask-question-index-exceeded-the-requested-question","errorCode":null,"errorMessage":"Ask question index exceeded the requested question list","messagePattern":"Ask question index exceeded the requested question list","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/ask.ts","lineNumber":1055,"sourceCode":"\t\t\t\ttimedOut: timedOut || undefined,\n\t\t\t};\n\n\t\t\tconst responseText = formatSingleQuestionResponse({\n\t\t\t\tselectedOptions,\n\t\t\t\tcustomInput,\n\t\t\t\tnote,\n\t\t\t\ttimedOut: timedOut || undefined,\n\t\t\t\tmulti: q.multi ?? false,\n\t\t\t});\n\n\t\t\treturn { content: [{ type: \"text\" as const, text: responseText }], details };\n\t\t}\n\n\t\tconst resultsByIndex: Array<QuestionResult | undefined> = Array.from({ length: params.questions.length });\n\t\tlet questionIndex = 0;\n\t\twhile (questionIndex < params.questions.length) {\n\t\t\tconst q = params.questions[questionIndex];\n\t\t\tif (!q) throw new Error(\"Ask question index exceeded the requested question list\");\n\t\t\tconst previous = resultsByIndex[questionIndex];\n\t\t\tconst navigation: NavigationControls = {\n\t\t\t\tallowBack: questionIndex > 0,\n\t\t\t\tallowForward: true,\n\t\t\t\tprogressText: `${questionIndex + 1}/${params.questions.length}`,\n\t\t\t};\n\t\t\tconst {\n\t\t\t\toptionLabels,\n\t\t\t\tselectedOptions,\n\t\t\t\tcustomInput,\n\t\t\t\tnote,\n\t\t\t\tnavigation: navAction,\n\t\t\t\tcancelled,\n\t\t\t\ttimedOut,\n\t\t\t} = await askQuestion(q, { previous, navigation });\n\n\t\t\tif (cancelled && !timedOut) {\n\t\t\t\tcontext.abort();","sourceCodeStart":1037,"sourceCodeEnd":1073,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/ask.ts#L1037-L1073","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the questions array is dense: contiguous indices 0..length-1 with a Question at each.","Construct with literal/array methods (map, filter with type narrowing) instead of index assignment on an empty array.","Filter out holes before calling: `questions.filter(Boolean)` then verify length matches expected."],"exampleFix":"// before (sparse)\nconst questions = [];\nquestions[0] = q1;\nquestions[2] = q3; // hole at index 1\n// after\nconst questions = [q1, q3]; // dense array","handlingStrategy":"validation","validationCode":"function assertDenseQuestions(questions: Question[]): Question[] {\n  if (!Array.isArray(questions)) throw new TypeError('questions must be an array');\n  if (questions.filter(Boolean).length !== questions.length) {\n    throw new TypeError('questions contains holes/undefined entries');\n  }\n  return questions;\n}","typeGuard":"function hasNoHoles<T>(arr: T[]): boolean {\n  return arr.length === arr.filter(() => true).length && arr.every(x => x !== undefined && x !== null);\n}","tryCatchPattern":null,"preventionTips":["Build questions arrays with literals or push/map, never index assignment into an empty array.","Sanitize deserialized question lists (Object.values of a map → sort by key → dense array).","Don't mutate the questions array while the tool is running."],"tags":["internal-invariant","array-validation","sdk"],"backgroundTag":"sparse-array-index-out-of-range","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}