musistudio/claude-code-router · error · Error
Invalid theme preference.
Error message
Invalid theme preference.
What it means
normalizeAppThemePreference only accepts the literal strings 'system', 'light', or 'dark'; any other value (including undefined/null/numbers) throws when normalizing app config.
Source
Thrown at packages/core/src/config/config.ts:411
const normalizedConfig = withSingleEnabledGlobalProfiles(config);
assertProviderApiKeysAreSafe(normalizedConfig);
const apiKeys = ensureGatewayApiKeys(normalizeApiKeys(normalizedConfig.APIKEYS, normalizedConfig.APIKEY).filter((apiKey) => !isDefaultSeedApiKey(apiKey)));
const pluginMigration = migrateKnownGatewayPluginConfigs(normalizedConfig.plugins);
await replacePersistedConfigSnapshot(sanitizeConfigForDisk({
...normalizedConfig,
theme: appThemePreferenceOverride ?? normalizedConfig.theme,
APIKEY: apiKeys[0]?.key ?? "",
APIKEYS: apiKeys,
plugins: pluginMigration.plugins
}), apiKeys);
return loadAppConfig();
}
function normalizeAppThemePreference(theme: unknown): AppConfig["theme"] {
if (theme === "system" || theme === "light" || theme === "dark") {
return theme;
}
throw new Error("Invalid theme preference.");
}
function enqueueAppConfigWrite<T>(operation: () => Promise<T>): Promise<T> {
const result = appConfigWriteQueue.then(operation, operation);
appConfigWriteQueue = result.then(
() => undefined,
() => undefined
);
return result;
}
function withSingleEnabledGlobalProfiles(config: AppConfig): AppConfig {
const profiles = enforceSingleEnabledGlobalProfilePerAgent(config.profile.profiles);
return {
...config,
Providers: config.Providers.map(normalizeProviderPresetCapabilities),
profile: synchronizeLegacyProfileConfig({
...config.profile,View on GitHub (pinned to 99f24806c6)
Solutions
- Set theme to "system", "light", or "dark" in the config file.
- Sanitize before saving: coerce unknown values to "system".
- Re-save config from the app's settings UI to rewrite a valid value.
Example fix
// before theme: config.theme // may be "Dark" // after theme: ["system","light","dark"].includes(config.theme) ? config.theme : "system"
Defensive patterns
Strategy: type-guard
Validate before calling
if (!['system','light','dark'].includes(cfg.theme)) cfg.theme = 'system';
Type guard
function isAppTheme(v: unknown): v is 'system' | 'light' | 'dark' {
return v === 'system' || v === 'light' || v === 'dark';
} Try / catch
catch (e) { if ((e as Error).message === 'Invalid theme preference.') { config.theme = 'system'; await save(config); } } Prevention
- Validate hand-edited configs before load.
- Write themes only from the settings UI.
When it happens
Trigger: Loading/saving app config where theme is not one of the three accepted literals — e.g. hand-edited config file, config written by an older/newer version, or a UI writing a raw enum.
Common situations: User edits config.json and types "Dark" or "auto"; migration writes theme: null.
Related errors
- ${issue.message}
- No Bot Gateway conversationRef is configured and no inbound
- The CCR artifact endpoint returned a non-media content type.
- The CCR media artifact exceeds the inline preview size limit
- Compressed CCR media artifacts are not accepted for inline p
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/44838dc8270bed8a.
Report an issue: GitHub.