From a0996396d60273af6b1490c68f1a6e4e727c4e9c Mon Sep 17 00:00:00 2001 From: Amolith Date: Sun, 5 Apr 2026 20:30:07 -0600 Subject: [PATCH] questionnaire: Guard empty options and dedup IDs When a question has no options and allowOther is false, the opts array is empty but optionIndex is 0. Accessing opts[0].isOther crashes with a TypeError on undefined. Add an early return when the selected option does not exist. Deduplicate question IDs at normalization time by appending _2, _3, etc. to collisions. Duplicate IDs caused answer map overwrites where only the last answer for a given ID survived. --- packages/questionnaire/src/index.ts | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/questionnaire/src/index.ts b/packages/questionnaire/src/index.ts index 7cd309ca6002bc9f0b12f2bd875c33475dc2bc5b..f617ec4349afeebd9654054d4ccb85a5bf89547f 100644 --- a/packages/questionnaire/src/index.ts +++ b/packages/questionnaire/src/index.ts @@ -101,12 +101,23 @@ export default function questionnaire(pi: ExtensionAPI) { return errorResult("Error: No questions provided"); } - // Normalize questions with defaults - const questions: Question[] = params.questions.map((q, i) => ({ - ...q, - label: q.label || `Q${i + 1}`, - allowOther: q.allowOther !== false, - })); + // Normalize questions with defaults and deduplicate IDs + const seenIds = new Set(); + const questions: Question[] = params.questions.map((q, i) => { + let id = q.id; + if (seenIds.has(id)) { + let suffix = 2; + while (seenIds.has(`${id}_${suffix}`)) suffix++; + id = `${id}_${suffix}`; + } + seenIds.add(id); + return { + ...q, + id, + label: q.label || `Q${i + 1}`, + allowOther: q.allowOther !== false, + }; + }); const isMulti = questions.length > 1; const totalTabs = questions.length + 1; // questions + Submit @@ -284,6 +295,7 @@ export default function questionnaire(pi: ExtensionAPI) { // Select option if (matchesKey(data, Key.enter) && q) { const opt = opts[optionIndex]; + if (!opt) return; // no options available if (opt.isOther) { inputMode = true; inputQuestionId = q.id;