zed-industries/zed · error

unregistered setting type {}

Error message

unregistered setting type {}

What it means

Zed's SettingsStore keeps setting values keyed by TypeId; entries appear only when a settings type is registered via SettingsStore::register_setting::<T>() (crates/settings/src/settings_store.rs:407), normally reached through T::register(cx) during app or test init. get::<T>() (crates/settings/src/settings_store.rs:449) unwraps that lookup and panics, printing the concrete Rust type name of the missing setting. That type name is the fastest clue to which init step was skipped.

Source

Thrown at crates/settings/src/settings_store.rs:449

        }

        let setting_value = entry.or_insert((registered_setting.settings_value)());
        let value = (registered_setting.from_settings)(&self.merged_settings);
        setting_value.set_global_value(value);
    }

    pub fn merged_settings(&self) -> &SettingsContent {
        &self.merged_settings
    }

    /// Get the value of a setting.
    ///
    /// Panics if the given setting type has not been registered, or if there is no
    /// value for this setting.
    pub fn get<T: Settings>(&self, path: Option<SettingsLocation>) -> &T {
        self.setting_values
            .get(&TypeId::of::<T>())
            .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()))
            .value_for_path(path)
            .downcast_ref::<T>()
            .expect("no default value for setting type")
    }

    /// Get the value of a setting.
    ///
    /// Does not panic
    pub fn try_get<T: Settings>(&self, path: Option<SettingsLocation>) -> Option<&T> {
        self.setting_values
            .get(&TypeId::of::<T>())
            .map(|value| value.value_for_path(path))
            .and_then(|value| value.downcast_ref::<T>())
    }

    /// Get all values from project specific settings
    pub fn get_all_locals<T: Settings>(&self) -> Vec<(WorktreeId, Arc<RelPath>, &T)> {
        self.setting_values

View on GitHub (pinned to 5a9b9558db)

Solutions

  1. Register the setting before any read: call MySettings::register(cx) in app startup, or set the store up in tests (SettingsStore::new(cx, ...) plus register_setting) before reading.
  2. Take the type name from the panic message, locate its Settings impl, and verify the path that calls its register actually executed.
  3. If the read may legitimately precede registration, use SettingsStore::try_get::<T>() (crates/settings/src/settings_store.rs:458) which returns Option instead of panicking.
  4. In tests, reuse the established settings fixture rather than ad-hoc reads.

Example fix

// before (test or early startup)
let value = MySettings::get_global(cx); // panics: unregistered setting type

// after
MySettings::register(cx);
let value = MySettings::get_global(cx);
Defensive patterns

Strategy: validation

Validate before calling

// startup / test setup: register before any read
MySettings::register(cx); // wraps SettingsStore::register_setting::<MySettings>()

// reads that may run before init completes:
if let Some(value) = SettingsStore::global(cx).read(cx).try_get::<MySettings>(None) {
    // use value
}

Prevention

When it happens

Trigger: Reading a setting whose registration never ran: SettingsStore::get(None or Some(location)) as T, or typed helpers like T::get_global(cx)/T::get(...) that route through it, in a process where T::register(cx) / register_setting::<T>() was not called first.

Common situations: GPUI unit tests reading a setting without the standard settings fixture in build_app; a new crate reading another crate's setting before that crate's init ran; entry points that skip the normal app init sequence; refactors moving register calls out of startup.

Related errors


AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20). Data as JSON: /api/errors/0b386cfc08cae99f. Report an issue: GitHub.