fix(providers): surface a warning on 404 model_not_found in OpenAI-compatible Check (port from 9router#2032) (#7103)

Root cause: validateOpenAICompatibleProvider's chat-completions probe fallback treated ANY 4xx other than 401/403/429/400 as a silent 'credentials valid' pass with no warning, so a bogus/non-standard model id (e.g. Featherless/OpenRouter vendor/model typos) went undetected at Check time. The first real request then hit the upstream 404 model_not_found and the per-model lockout, holding the model unavailable for the configured reset window with no prior indication anything was wrong.

User-visible effect: 'Check' now returns valid:true with an explicit warning (including the upstream error message when parseable) whenever the chat probe answers 404, so a bad model id is caught before it reaches production traffic and the lockout.

Reported-by: advane204f (https://github.com/decolua/9router/issues/2032)
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-07-16 14:13:18 -03:00
committed by GitHub
parent fd2aaff920
commit 39222525ea
3 changed files with 73 additions and 0 deletions

View File

@@ -459,6 +459,31 @@ export async function validateOpenAICompatibleProvider({ apiKey, providerSpecifi
};
}
// #2032: a 404 on the chat probe commonly means the requested model id
// does not exist at this provider (OpenAI-compatible `model_not_found`,
// e.g. Featherless/OpenRouter-style `vendor/model` typos). Credentials
// are still valid (the endpoint responded), but silently passing this
// hides the bad model id from the user until a real request later trips
// the per-model lockout — surface it as a warning at Check time instead.
if (chatRes.status === 404) {
let modelNotFoundDetail = "";
try {
const body: any = await chatRes.json();
const err = body?.error;
if (typeof err?.message === "string" && err.message.trim()) {
modelNotFoundDetail = `: ${err.message.trim()}`;
}
} catch {
// Non-JSON or unreadable body — fall through with the generic warning.
}
return {
valid: true,
error: null,
method: "inference_available",
warning: `Model ID may not exist at this provider (404)${modelNotFoundDetail}`,
};
}
// 4xx other than auth (e.g. 400 bad model, 422) usually means auth passed
if (chatRes.status >= 400 && chatRes.status < 500) {
return {