{"record":{"id":"ff9277b6480d0e2a","repo":"Yeachan-Heo/oh-my-codex","slug":"path-must-be-a-non-empty-string-array","errorCode":null,"errorMessage":"${path} must be a non-empty string array","messagePattern":"(.+?) must be a non-empty string array","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/question/state.ts","lineNumber":298,"sourceCode":"    }\n  }\n\n  try {\n    return await fn();\n  } finally {\n    try {\n      const currentOwner = await readFile(ownerPath, 'utf8');\n      if (currentOwner.trim() === ownerToken) {\n        await rm(lockDir, { recursive: true, force: true });\n      }\n    } catch {\n    }\n  }\n}\n\nfunction validateStringArray(value: unknown, path: string): string[] {\n  if (!Array.isArray(value) || !value.every((item) => typeof item === 'string' && item.trim().length > 0)) {\n    throw new Error(`${path} must be a non-empty string array`);\n  }\n  return value;\n}\n\nfunction assertNoDuplicateValues(values: string[], path: string): void {\n  const seen = new Set<string>();\n  for (const value of values) {\n    if (seen.has(value)) throw new Error(`${path} must not contain duplicate values: ${value}`);\n    seen.add(value);\n  }\n}\n\nfunction expectedSelectedLabelsForValues(\n  question: NormalizedQuestionItem,\n  selectedValues: string[],\n  otherText: string | undefined,\n): string[] {\n  const optionLabelsByValue = new Map(question.options.map((option) => [option.value, option.label]));","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/question/state.ts#L280-L316","documentation":"validateStringArray requires an array where every element is a non-empty, non-whitespace string. It is used to validate answer.selected_values and answer.selected_labels on submitted question answers; anything else (non-array, empty array elements, blanks, numbers) throws with the offending path.","triggerScenarios":"Submitting an answer whose selected_values or selected_labels is undefined, not an array, contains empty strings, whitespace-only strings, or non-string values; e.g. answers[i].answer.selected_values = [] is fine only if length checks elsewhere pass, but [''] or 'opt1' (a bare string) throw here.","commonSituations":"Clients building answers from raw form state without normalizing empty inputs; JSON payloads where a single select sends a scalar instead of a 1-element array; trimming side effects producing '' after whitespace-only input.","solutions":["Ensure selected_values and selected_labels are always arrays of trimmed, non-empty strings before submit","Filter out empty/blank entries: values.map(v => v.trim()).filter(Boolean)","Add a client-side schema check (e.g. zod) mirroring: array of non-empty strings"],"exampleFix":"// before\nanswer.selected_values = rawInput; // could be '' or undefined\n// after\nanswer.selected_values = (Array.isArray(rawInput) ? rawInput : [rawInput]).map((v) => String(v).trim()).filter((v) => v.length > 0);","handlingStrategy":"validation","validationCode":"function isNonEmptyStringArray(v: unknown): v is string[] {\n  return Array.isArray(v) && v.every((x) => typeof x === 'string' && x.trim().length > 0);\n}\nif (!isNonEmptyStringArray(answer.selected_values)) throw new Error('bad selected_values');","typeGuard":"function isNonEmptyStringArray(v: unknown): v is string[] {\n  return Array.isArray(v) && v.every((x) => typeof x === 'string' && x.trim().length > 0);\n}","tryCatchPattern":"try { await submit(recordPath, answers); } catch (e) { if (/must be a non-empty string array/.test((e as Error).message)) { highlightInvalidField((e as Error).message); return; } throw e; }","preventionTips":["Normalize and trim user selections before building the answer","Mirror the array-of-nonempty-strings rule with a client-side schema (zod/json-schema)"],"tags":["validation","answers","question-submit"],"backgroundTag":"schema-validation-failed","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}