laurent22/joplin · error · Error

Whisper config is not an object

Error message

Whisper config is not an object

What it means

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`.

Source

Thrown at packages/app-mobile/services/voiceTyping/whisper.ts:21

import Logger from '@joplin/utils/Logger';
import { rtrimSlashes } from '@joplin/utils/path';
import { dirname, join } from 'path';
import { openSession, test as testWhisper, Session as WhisperSession } from '@joplin/whisper-voice-typing';
import { SpeechToTextCallbacks, VoiceTypingProvider, VoiceTypingSession } from './VoiceTyping';
import { languageCodeOnly, stringByLocale } from '@joplin/lib/locale';
import { Platform } from 'react-native';

const logger = Logger.create('voiceTyping/whisper');

class WhisperConfig {
	public prompts: Map<string, string> = new Map();
	public supportsShortAudioCtx = false;
	public stringReplacements: [string, string][] = [];
	public regexReplacements: [RegExp, string][] = [];

	public constructor(json: unknown) {
		const errorPrefix = 'Whisper config';
		if (typeof json !== 'object') throw new Error('Whisper config is not an object');

		const processPrompts = () => {
			if (!('prompts' in json)) return;
			if (typeof json.prompts !== 'object') {
				throw new Error(`${errorPrefix}: Field "prompts" is not an object`);
			}

			for (const [key, value] of Object.entries(json.prompts)) {
				if (typeof value !== 'string') {
					throw new Error(`${errorPrefix}: Value for key ${key} is ${typeof value}, not string.`);
				}
				this.prompts.set(key, value);
			}
		};
		const processOutputSettings = () => {
			if (!('output' in json)) return;
			if (typeof json.output !== 'object') {
				throw new Error(`${errorPrefix}: Field "output" is not an object`);

View on GitHub (pinned to 2654b33620)

Solutions

  1. Validate the parsed config shape before constructing: `if (!json || typeof json !== 'object' || Array.isArray(json)) ...`.
  2. Re-download the model bundle to restore a known-good `config.json`.
  3. If shipping custom configs, schema-validate against the expected WhisperConfig shape at authoring time.

Example fix

// before
if (typeof json !== 'object') throw new Error('Whisper config is not an object');

// after
if (!json || typeof json !== 'object' || Array.isArray(json)) {
  throw new Error('Whisper config is not an object');
}
Defensive patterns

Strategy: type-guard

Validate before calling

const isConfigObject = (json: unknown): json is Record<string, unknown> =>
  !!json && typeof json === 'object' && !Array.isArray(json);

if (!isConfigObject(parsed)) {
  throw new Error('Whisper config file is malformed at the root');
}

Type guard

const isWhisperConfigRoot = (json: unknown): json is Record<string, unknown> =>
  json !== null && typeof json === 'object' && !Array.isArray(json);

Try / catch

null

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12). Data as JSON: /api/errors/25a868052796c400. Report an issue: GitHub.