fix(config): warn when root base_url is set with non-DeepSeek provider (#1308)

Common footgun: users set api_provider = \"ollama\" (or vllm /
openrouter / etc.) at the top of config.toml and add a top-level
base_url = \"http://my-server\" alongside it. The root base_url field
is only read for DeepSeek/DeepseekCN (and a back-compat sniff for
NvidiaNim) — for every other provider it's silently ignored, and the
user can't figure out why their override doesn't apply.

Add a one-line tracing::warn at config load time pointing the user at
the matching `[providers.<name>]` table or the corresponding
`*_BASE_URL` env var. Skipped if the per-provider table already has
its own `base_url` (which would win anyway).

No behavior change to URL resolution.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hunter Bown
2026-05-10 00:29:28 -05:00
parent 829270a8e7
commit 503140d8d5
2 changed files with 56 additions and 0 deletions
+5
View File
@@ -23,6 +23,11 @@ published.
### Fixed
- **Hint when root `base_url` is set with a non-DeepSeek provider
(#1308)** — config load now logs a warning telling the user to
move the URL under the matching `[providers.<name>]` table or use
the `*_BASE_URL` env var. Closes the silent-ignore footgun for
Ollama / vLLM / OpenAI-compatible setups.
- **Insecure base-URL error message is more discoverable (#1303)** —
the rejection now spells out which env var to set (with underscores
visible), notes that loopback hosts are auto-allowed, and shows a
+51
View File
@@ -1078,9 +1078,60 @@ impl Config {
apply_requirements(&mut config)?;
normalize_model_config(&mut config);
config.validate()?;
config.warn_on_misplaced_root_base_url();
Ok(config)
}
/// Surface a one-line warning when the user has set the legacy root
/// `base_url` field but their active provider is not DeepSeek (the only
/// provider that actually reads that field, plus an NvidiaNim back-compat
/// sniff). Common confusion: users add `base_url = "..."` at the top of
/// `~/.deepseek/config.toml` for ollama / vllm / openai-compat servers
/// and wonder why it's silently ignored (#1308).
fn warn_on_misplaced_root_base_url(&self) {
let Some(root_base) = self.base_url.as_deref().map(str::trim) else {
return;
};
if root_base.is_empty() {
return;
}
let provider = self.api_provider();
if matches!(provider, ApiProvider::Deepseek | ApiProvider::DeepseekCN) {
return;
}
if matches!(provider, ApiProvider::NvidiaNim)
&& root_base.contains("integrate.api.nvidia.com")
{
return;
}
// Only warn if the per-provider table doesn't have an explicit
// `base_url`, because if it does, the per-provider one wins and the
// root field is just dead config — no behavior surprise.
let has_provider_base = self
.provider_config_for(provider)
.and_then(|p| p.base_url.as_deref().map(str::trim))
.is_some_and(|s| !s.is_empty());
if has_provider_base {
return;
}
let table = match provider {
ApiProvider::Openai => "providers.openai",
ApiProvider::Openrouter => "providers.openrouter",
ApiProvider::Novita => "providers.novita",
ApiProvider::Fireworks => "providers.fireworks",
ApiProvider::Sglang => "providers.sglang",
ApiProvider::Vllm => "providers.vllm",
ApiProvider::Ollama => "providers.ollama",
ApiProvider::NvidiaNim => "providers.nvidia_nim",
ApiProvider::Deepseek | ApiProvider::DeepseekCN => return,
};
tracing::warn!(
"Top-level `base_url = \"{root_base}\"` is ignored for the {provider:?} provider. \
Move it under `[{table}]` (e.g. `[{table}]\\nbase_url = \"...\"`) \
or set the corresponding `*_BASE_URL` env var. (#1308)"
);
}
/// Validate that critical config fields are present.
pub fn validate(&self) -> Result<()> {
if let Some(provider) = self.provider.as_deref()