cjpais/Handy · warning
No handler for setting: ${String(key)}
Error message
No handler for setting: ${String(key)} What it means
settingsStore.updateSetting optimistically patches local Zustand state, then looks up a per-key async updater in the settingUpdaters map (settingsStore.ts line 76) to persist the value through a Tauri command. Keys 'bindings' and 'selected_model' are excluded because they are persisted through dedicated flows. For any other key with no map entry this warning fires: the UI shows the new value immediately, but the backend never persists it, so the setting silently reverts on the next reload.
Source
Thrown at src/stores/settingsStore.ts:332
key: K,
value: Settings[K],
) => {
const { settings, setUpdating } = get();
const updateKey = String(key);
const originalValue = settings?.[key];
setUpdating(updateKey, true);
try {
set((state) => ({
settings: state.settings ? { ...state.settings, [key]: value } : null,
}));
const updater = settingUpdaters[key];
if (updater) {
await updater(value);
} else if (key !== "bindings" && key !== "selected_model") {
console.warn(`No handler for setting: ${String(key)}`);
}
} catch (error) {
console.error(`Failed to update setting ${String(key)}:`, error);
if (settings) {
set({ settings: { ...settings, [key]: originalValue } });
}
} finally {
setUpdating(updateKey, false);
}
},
// Reset a setting to its default value
resetSetting: async (key) => {
const { defaultSettings } = get();
if (defaultSettings) {
const defaultValue = defaultSettings[key];
if (defaultValue !== undefined) {
await get().updateSetting(key, defaultValue as any);View on GitHub (pinned to fbd4e15fa1)
Solutions
- Add an updater entry to settingUpdaters mapping the key to its persist command (e.g. new_option: (v) => commands.changeNewOptionSetting(v as boolean))
- If the key is intentionally persisted elsewhere, add it to the exclusion condition alongside 'bindings' and 'selected_model' with a comment
- Make coverage compile-enforced: type settingUpdaters as Record<keyof Settings, updater | symbol> and fill gaps with an explicit UNHANDLED marker so missing keys fail typecheck
- Add a unit test enumerating Object.keys(defaultSettings) minus the exclusion list against Object.keys(settingUpdaters)
Example fix
// before: 'new_option' exists in Settings, toggle works, warning fires, value never persists
// after: src/stores/settingsStore.ts
const settingUpdaters: { [K in keyof Settings]?: (value: Settings[K]) => Promise<unknown> } = {
// ...existing entries...
new_option: (value) => commands.changeNewOptionSetting(value as boolean),
}; Defensive patterns
Strategy: type-guard
Validate before calling
// Unit test: every persisted Settings key must have an updater (or be excluded)
const EXCLUDED = new Set(["bindings", "selected_model"]);
const missing = (Object.keys(defaultSettings) as (keyof Settings)[])
.filter((k) => !EXCLUDED.has(k) && !settingUpdaters[k]);
if (missing.length) throw new Error(`No handler for setting: ${missing.join(", ")}`); Type guard
const hasUpdater = (key: keyof Settings): boolean => key === "bindings" || key === "selected_model" || Boolean(settingUpdaters[key]);
Prevention
- Whenever you add a field to Settings, add its settingUpdaters entry in the same commit
- Keep the exclusion list ('bindings', 'selected_model') documented with why they bypass the map
- Treat this console.warn in dev as a bug: the setting currently does not persist
When it happens
Trigger: Adding a new field to the Settings/AppSettings type and wiring a toggle to updateSetting('newKey', v) without adding newKey: (v) => commands.changeNewKeySetting(v) to settingUpdaters; renaming a key in the type but not the map; a typo between the UI's key string and the map's key.
Common situations: Feature work adding a new preference; refactors that rename settings; review churn where the Rust command exists but the TS map entry was forgotten.
Related errors
- Missing metadata for locale "${code}" in languages.ts
- Failed to sync language from settings:
- Failed to sync theme from settings:
- result.error
- Failed to update binding
AI-assisted analysis of cjpais/Handy@fbd4e15fa1 (2026-08-17).
Data as JSON: /api/errors/77be41cc99fca270.
Report an issue: GitHub.