Hmbown/CodeWhale · error
custom provider ' ' must set [providers. ].kind =…
Error message
custom provider '{provider_id}' must set [providers.{provider_id}].kind = "openai-compatible" What it means
Thrown when validating a custom provider table: every entry under `[providers.<id>]` must declare `kind = "openai-compatible"` (case-insensitive; underscores allowed for hyphens). A custom provider without this exact kind marker cannot be constructed as a table, because the library only knows how to build OpenAI-compatible custom providers.
Solutions
- Add `kind = "openai-compatible"` inside the `[providers.<provider_id>]` table.
- Correct the `kind` value to exactly "openai-compatible" (case/underscore-insensitive).
- If the provider needs a non-OpenAI protocol, do not register it as a custom provider; use a built-in provider kind instead.
Example fix
// before [providers.my_llm] base_url = "http://localhost:8080/v1" // after [providers.my_llm] kind = "openai-compatible" base_url = "http://localhost:8080/v1"
Defensive patterns
Strategy: validation
Validate before calling
fn custom_provider_table_valid(t: &toml::Table) -> bool {
t.get("kind")
.and_then(|k| k.as_str())
.map(|k| k.trim().to_ascii_lowercase().replace('_', "-") == "openai-compatible")
.unwrap_or(false)
} Try / catch
match load_config() {
Err(e) if e.to_string().contains("openai-compatible") => {
eprintln!("{e}");
// add kind = "openai-compatible" to the offending [providers.<id>] table
}
other => other,
} Prevention
- Always include `kind = "openai-compatible"` in every custom provider table.
- Use a config template/snippet for custom providers instead of writing tables from scratch.
- Validate config.toml after hand-editing custom provider sections.
When it happens
Trigger: Defining a custom provider in config.toml whose `[providers.<provider_id>]` table is missing the `kind` key, or sets it to something other than "openai-compatible" (e.g. "anthropic", "ollama", or an empty value) — checked via the table validation reached from config loading/custom-provider construction.
Common situations: User adds a custom provider section and forgets `kind`; copies a provider block from docs for a native provider and pastes it as a custom entry; typo like `kind = "openai_compatible"` with the wrong separator is fine (normalized), but `kind = "custom"` fails.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- custom provider base URL is invalid
- custom providers store base_url in their named
- Invalid default_text_model
- Invalid provider ' ': expected .
- .context_window must be greater than 0
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/e2634c8a5dd9ff80.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/lib.rs:2530
.extras
.get(provider_id)
.and_then(toml::Value::as_table)
.with_context(|| {
format!(
"custom provider '{provider_id}' requires a matching [providers.{provider_id}] table"
)
})?;
let compatible = table
.get("kind")
.and_then(toml::Value::as_str)
.is_some_and(|kind| {
kind.trim()
.to_ascii_lowercase()
.replace('_', "-")
.eq("openai-compatible")
});
if !compatible {
bail!(
"custom provider '{provider_id}' must set [providers.{provider_id}].kind = \"openai-compatible\""
);
}
Ok(table)
}
fn named_custom_provider_config(&self) -> Option<ProviderConfigToml> {
let provider_id = self.named_custom_provider_id()?;
self.named_custom_provider_table(provider_id).ok()?;
self.providers
.extras
.get(provider_id)
.cloned()?
.try_into()
.ok()
}
/// Mutable access to a custom provider's `[providers.<id>]` table,View on GitHub (pinned to 73e0f67d83)