sigoden/aichat · error
Unknown client
Error message
Unknown client '{client}' What it means
Raised by the `create_config` macro expansion (src/client/macros.rs:99): after trying every builtin client and the generic OpenAI-compatible config path, the given client name matched nothing, so creation aborts with "Unknown client '<name>'". The client name in config is not one this build supports.
Solutions
- Fix the client name to one of the supported values (see list_client_names output).
- If the provider is OpenAI-compatible, set client_config type to the OpenAI-compatible client name and provide api_base and api_key.
- Upgrade or downgrade the library so the desired client exists in this build.
- Check the CHANGELOG for client renames if this worked before an upgrade.
Example fix
// before (config) "client": "openiai" // after "client": "openai"
Defensive patterns
Strategy: validation
Validate before calling
let supported = list_client_names(&config);
if !supported.iter().any(|n| n.as_str() == client) {
anyhow::bail!("client '{}' not supported; choose one of {:?}", client, supported);
} Type guard
fn is_known_client(client: &str, config: &Config) -> bool {
list_client_names(config).iter().any(|n| n.as_str() == client)
} Try / catch
match create_config(client).await {
Err(e) if e.to_string().starts_with("Unknown client") => {
eprintln!("Supported clients: {:?}", list_client_names(&config));
}
other => other,
} Prevention
- Copy client names from list_client_names output rather than typing them.
- For custom providers use the openai-compatible path with type/api_base/api_key set.
- Check client renames after library upgrades.
- Validate config files with a schema check before loading.
When it happens
Trigger: Calling create_config (via client macro) with a client string that is not one of the macro-listed client names and not resolvable as an OpenAI-compatible client (no matching OpenAICompatibleClient::NAME type / api_base setup).
Common situations: Typo in config's client field (e.g. 'openiai'); using a client name from a different/newer library version; configuring a provider that is only reachable via the openai-compatible path but missing api_base/type fields; renamed client in an upgrade.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
AI-assisted analysis of sigoden/aichat@82976d349a (2026-09-09).
Data as JSON: /api/errors/c150f440b8d01d3d.
Report an issue: GitHub.
Appendix: source
Thrown at src/client/macros.rs:99
})
}
pub fn list_client_types() -> Vec<&'static str> {
let mut client_types: Vec<_> = vec![$($client::NAME,)+];
client_types.extend($crate::client::OPENAI_COMPATIBLE_PROVIDERS.iter().map(|(name, _)| *name));
client_types
}
pub async fn create_client_config(client: &str) -> anyhow::Result<(String, serde_json::Value)> {
$(
if client == $client::NAME && client != $crate::client::OpenAICompatibleClient::NAME {
return create_config(&$client::PROMPTS, $client::NAME).await
}
)+
if let Some(ret) = create_openai_compatible_client_config(client).await? {
return Ok(ret);
}
anyhow::bail!("Unknown client '{}'", client)
}
static ALL_CLIENT_NAMES: std::sync::OnceLock<Vec<String>> = std::sync::OnceLock::new();
pub fn list_client_names(config: &$crate::config::Config) -> Vec<&'static String> {
let names = ALL_CLIENT_NAMES.get_or_init(|| {
config
.clients
.iter()
.flat_map(|v| match v {
$(ClientConfig::$config(c) => vec![$client::name(c).to_string()],)+
ClientConfig::Unknown => vec![],
})
.collect()
});
names.iter().collect()
}
View on GitHub (pinned to 82976d349a)