Hmbown/CodeWhale · error · anyhow::Error

Unknown feature flag: {key}

Error message

Unknown feature flag: {key}

What it means

Config validation (crates/tui/src/config.rs:4385) iterates the [features] table and rejects any key that is_known_feature_key does not recognize. Feature flags gate real code paths, so an unknown key (typo or retired flag) fails load instead of silently doing nothing.

Source

Thrown at crates/tui/src/config.rs:4385

        match validate_kimi_code_api_model_id(
            active_provider,
            &self.deepseek_base_url(),
            &self.default_model(),
        ) {
            Err(error) if error == KIMI_CODE_CLAUDE_ALIAS_GUIDANCE => {
                return Err(SafeConfigDiagnostic::KimiCodeClaudeAlias.into());
            }
            result => result.map_err(anyhow::Error::msg)?,
        }
        if let Some(ref key) = self.api_key
            && key.trim().is_empty()
        {
            anyhow::bail!("api_key cannot be empty string");
        }
        if let Some(features) = &self.features {
            for key in features.entries.keys() {
                if !is_known_feature_key(key) {
                    anyhow::bail!("Unknown feature flag: {key}");
                }
            }
        }
        // Validate the model against the *active provider's* name space, not
        // against DeepSeek's. `canonical_model_id_for_provider` is the
        // equal-treatment resolver: it applies each family's own canonical map
        // (GLM via Z.ai, Kimi, MiniMax, …) and passes unknown ids through, so
        // it rejects only what the provider genuinely cannot serve. Validating
        // with the DeepSeek-only `normalize_model_name` bricked every config
        // whose provider owns a non-DeepSeek family — including ones our own
        // setup wizard writes (`provider = "zai"`, `GLM-5.2`). (#4829)
        if let Some(model) = self.default_text_model.as_deref()
            && !model.trim().eq_ignore_ascii_case("auto")
            && !provider_passes_model_through(self.api_provider())
            && !self.active_provider_preserves_custom_base_url_model()
            && canonical_model_id_for_provider(self.api_provider(), model).is_none()
        {
            let provider = self.api_provider();

View on GitHub (pinned to 8880682c63)

Solutions

  1. Check the release notes/CHANGELOG for the exact current flag names
  2. Fix or remove the typo'd key from [features]
  3. If the flag was retired, delete it - its behavior is either default or gone
  4. Upgrade the binary if the docs you copied from are newer than what you run

Example fix

# config.toml - before
[features]
beter_context = true

# config.toml - after
[features]
better_context = true
Defensive patterns

Strategy: validation

Validate before calling

for key in features_map.keys() {
    ensure!(is_known_feature_key(key), "unknown feature flag {key}");
}

Type guard

fn feature_flag_known(key: &str, known: &[&str]) -> bool { known.contains(&key) }

Try / catch

// In config tooling: filter flags against the running binary's known set
let unknown: Vec<_> = cfg.features.entries.keys().filter(|k| !is_known_feature_key(k)).collect();
if !unknown.is_empty() { bail!("unknown flags: {unknown:?}"); }

Prevention

When it happens

Trigger: A typo'd flag name (beter_context vs better_context); a flag renamed or removed in an upgrade; flags copied from newer-version docs into an older binary.

Common situations: Version skew between docs and the installed binary; hand-merging feature sections between configs; flags that existed in forks.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/50e141787502f6d0. Report an issue: GitHub.