{"record":{"id":"12ce31a8af49c269","repo":"laurent22/joplin","slug":"errorprefix-values-for-key-must-be-arrays","errorCode":null,"errorMessage":"${errorPrefix}: values for ${key} must be arrays","messagePattern":"(.+?): values for (.+?) must be arrays","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/app-mobile/services/voiceTyping/whisper.ts","lineNumber":50,"sourceCode":"\t\t\t\t}\n\t\t\t\tthis.prompts.set(key, value);\n\t\t\t}\n\t\t};\n\t\tconst processOutputSettings = () => {\n\t\t\tif (!('output' in json)) return;\n\t\t\tif (typeof json.output !== 'object') {\n\t\t\t\tthrow new Error(`${errorPrefix}: Field \"output\" is not an object`);\n\t\t\t}\n\n\t\t\tconst getReplacements = (key: string, value: unknown) => {\n\t\t\t\tif (!Array.isArray(value)) {\n\t\t\t\t\tthrow new Error(`${errorPrefix}: ${key} must be an array`);\n\t\t\t\t}\n\n\t\t\t\tconst results: [string, string][] = [];\n\t\t\t\tfor (const replacement of value) {\n\t\t\t\t\tif (!Array.isArray(replacement)) {\n\t\t\t\t\t\tthrow new Error(`${errorPrefix}: values for ${key} must be arrays`);\n\t\t\t\t\t}\n\t\t\t\t\tif (typeof replacement[0] !== 'string' || typeof replacement[1] !== 'string') {\n\t\t\t\t\t\tthrow new Error(`${errorPrefix}: values for ${key} must be pairs of strings`);\n\t\t\t\t\t}\n\n\t\t\t\t\tresults.push([replacement[0], replacement[1]]);\n\t\t\t\t}\n\t\t\t\treturn results;\n\t\t\t};\n\n\t\t\tif ('stringReplacements' in json.output) {\n\t\t\t\tthis.stringReplacements = getReplacements('stringReplacements', json.output.stringReplacements);\n\t\t\t}\n\n\t\t\tif ('regexReplacements' in json.output) {\n\t\t\t\tthis.regexReplacements = getReplacements('regexReplacements', json.output.regexReplacements).map(([key, value]) => {\n\t\t\t\t\treturn [new RegExp(key, 'g'), value];\n\t\t\t\t});","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/app-mobile/services/voiceTyping/whisper.ts#L32-L68","documentation":"Thrown inside `getReplacements` when iterating the replacement array and an individual entry is not itself an array. Each entry must be a `[pattern, replacement]` pair (a two-element array).","triggerScenarios":"Config like `{ \"stringReplacements\": [ \"foo\", [\"a\",\"b\"] ] }` where one of the elements is not an array (e.g. a stray string).","commonSituations":"Authoring error mixing flat strings with pairs; partial migration of an older format.","solutions":["Make every entry a two-element array.","Re-download the model bundle.","Schema-validate with `items: { type: 'array', items: { type: 'string' }, minItems: 2 }`."],"exampleFix":"// before\n\"stringReplacements\": [\"foo\", [\"a\",\"b\"]]\n\n// after\n\"stringReplacements\": [[\"foo\",\"bar\"], [\"a\",\"b\"]]","handlingStrategy":"validation","validationCode":"for (const entry of config.output.stringReplacements ?? []) {\n  if (!Array.isArray(entry)) {\n    throw new Error('Whisper config: each replacement entry must be an array');\n  }\n}","typeGuard":"const isPairArray = (v: unknown): v is unknown[] =>\n  Array.isArray(v) && v.length >= 2;","tryCatchPattern":"null","preventionTips":["Make each replacement entry a two-element array.","Schema-validate with items.type = array.","Re-download the bundle on validation failure."],"tags":["voice-typing","whisper","config","validation"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}