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
- Check the release notes/CHANGELOG for the exact current flag names
- Fix or remove the typo'd key from [features]
- If the flag was retired, delete it - its behavior is either default or gone
- 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
- Copy flag names from the docs matching your binary's version
- Diff [features] against the CHANGELOG when upgrading
- A typo'd flag fails the whole config load - lint it before launch
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
- Invalid provider '{provider}': expected {}.
- ${name} is required
- ${names.join(" or ")} is required
- ${name} is required
- version must be a semantic release identifier
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/50e141787502f6d0.
Report an issue: GitHub.