{"record":{"id":"25a868052796c400","repo":"laurent22/joplin","slug":"whisper-config-is-not-an-object","errorCode":null,"errorMessage":"Whisper config is not an object","messagePattern":"Whisper config is not an object","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/app-mobile/services/voiceTyping/whisper.ts","lineNumber":21,"sourceCode":"import Logger from '@joplin/utils/Logger';\nimport { rtrimSlashes } from '@joplin/utils/path';\nimport { dirname, join } from 'path';\nimport { openSession, test as testWhisper, Session as WhisperSession } from '@joplin/whisper-voice-typing';\nimport { SpeechToTextCallbacks, VoiceTypingProvider, VoiceTypingSession } from './VoiceTyping';\nimport { languageCodeOnly, stringByLocale } from '@joplin/lib/locale';\nimport { Platform } from 'react-native';\n\nconst logger = Logger.create('voiceTyping/whisper');\n\nclass WhisperConfig {\n\tpublic prompts: Map<string, string> = new Map();\n\tpublic supportsShortAudioCtx = false;\n\tpublic stringReplacements: [string, string][] = [];\n\tpublic regexReplacements: [RegExp, string][] = [];\n\n\tpublic constructor(json: unknown) {\n\t\tconst errorPrefix = 'Whisper config';\n\t\tif (typeof json !== 'object') throw new Error('Whisper config is not an object');\n\n\t\tconst processPrompts = () => {\n\t\t\tif (!('prompts' in json)) return;\n\t\t\tif (typeof json.prompts !== 'object') {\n\t\t\t\tthrow new Error(`${errorPrefix}: Field \"prompts\" is not an object`);\n\t\t\t}\n\n\t\t\tfor (const [key, value] of Object.entries(json.prompts)) {\n\t\t\t\tif (typeof value !== 'string') {\n\t\t\t\t\tthrow new Error(`${errorPrefix}: Value for key ${key} is ${typeof value}, not string.`);\n\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`);","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/app-mobile/services/voiceTyping/whisper.ts#L3-L39","documentation":"Thrown by the `WhisperConfig` constructor when the parsed JSON config passed to it is not an object (e.g. it is a number, string, array, or null). This is the top-level shape validation before reading any fields like `prompts` or `output`.","triggerScenarios":"Constructing `new WhisperConfig(json)` where `json` came from `JSON.parse(...)` of a `config.json` file whose root value is a primitive, an array, or `null`. `typeof null === 'object'` is a footgun but `null` will pass this check and fail later — arrays and primitives are caught here.","commonSituations":"Corrupted or hand-edited `config.json` next to a downloaded whisper model; an empty file parsed to a non-object; a model bundle shipping a malformed config.","solutions":["Validate the parsed config shape before constructing: `if (!json || typeof json !== 'object' || Array.isArray(json)) ...`.","Re-download the model bundle to restore a known-good `config.json`.","If shipping custom configs, schema-validate against the expected WhisperConfig shape at authoring time."],"exampleFix":"// before\nif (typeof json !== 'object') throw new Error('Whisper config is not an object');\n\n// after\nif (!json || typeof json !== 'object' || Array.isArray(json)) {\n  throw new Error('Whisper config is not an object');\n}","handlingStrategy":"type-guard","validationCode":"const isConfigObject = (json: unknown): json is Record<string, unknown> =>\n  !!json && typeof json === 'object' && !Array.isArray(json);\n\nif (!isConfigObject(parsed)) {\n  throw new Error('Whisper config file is malformed at the root');\n}","typeGuard":"const isWhisperConfigRoot = (json: unknown): json is Record<string, unknown> =>\n  json !== null && typeof json === 'object' && !Array.isArray(json);","tryCatchPattern":"null","preventionTips":["Schema-validate config.json before constructing WhisperConfig.","Treat null as invalid even though typeof null === 'object'.","Re-download the model bundle if config validation fails."],"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"}