{"record":{"id":"1ed560582b7fdfdd","repo":"decolua/9router","slug":"unknown-provider-providerinput","errorCode":null,"errorMessage":"Unknown provider: ${providerInput}","messagePattern":"Unknown provider: (.+?)","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"src/sse/handlers/fetch.js","lineNumber":120,"sourceCode":"      log,\n      comboName: providerInput,\n      comboStrategy,\n      comboStickyLimit\n    });\n  }\n\n  return handleSingleProviderFetch(body, providerInput, request, apiKey, settings);\n}\n\nasync function handleSingleProviderFetch(body, providerInput, request, apiKey, settings) {\n  const targetUrl = body.url;\n  const format = body.format;\n  const maxCharacters = body.max_characters;\n  const providerId = resolveProviderId(providerInput);\n  const resolvedProvider = AI_PROVIDERS[providerId];\n\n  if (!resolvedProvider) {\n    log.warn(\"FETCH\", \"Unknown provider\", { provider: providerInput });\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, `Unknown provider: ${providerInput}`);\n  }\n\n  const providerConfig = resolvedProvider.fetchConfig;\n  if (!providerConfig) {\n    log.warn(\"FETCH\", \"Provider does not support web fetch\", { provider: providerId });\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, `Provider ${providerId} does not support web fetch`);\n  }\n\n  if (providerInput !== providerId) {\n    log.info(\"ROUTING\", `${providerInput} → ${providerId}`);\n  } else {\n    log.info(\"ROUTING\", `Provider: ${providerId}`);\n  }\n\n  // No-auth fetch path (kept for parity though no current fetch provider sets noAuth)\n  if (resolvedProvider.noAuth) {\n    log.info(\"AUTH\", `\\x1b[32m${providerId} no-auth mode\\x1b[0m`);","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/sse/handlers/fetch.js#L102-L138","documentation":"handleSingleProviderFetch resolves the incoming provider/model string via resolveProviderId() and looks it up in the AI_PROVIDERS registry. If no provider matches, it returns HTTP 400 'Unknown provider: <input>'. Unlike chat, provider IS the model here, so an unknown model alias also lands here.","triggerScenarios":"POSTing {model:'gpt-4o'} when no such fetch-capable provider/model is registered; typos ('jinia', 'Jina ' with trailing space); a provider name that exists for chat but not for fetch; stale client config after a provider was renamed or removed from the registry.","commonSituations":"Copying a model name from chat code into the fetch endpoint; using a provider alias removed in an upgrade; environment where the provider registry differs from the client's hardcoded list; sending a combo name that was deleted from the dashboard.","solutions":["Check the spelling against the provider list shown in the 9Router dashboard providers page","Use the exact provider/model id as registered in open-sse/providers/registry (resolveProviderId handles case/alias, but not arbitrary names)","If the provider exists for chat but not fetch, verify it has a fetchConfig in the registry - only fetch-capable providers resolve here","Update the client's model list after upgrading 9Router (registry changes between versions)"],"exampleFix":"// before\n{ model: 'jina reader' }\n// after\n{ model: 'jina' }  // exact registered provider id","handlingStrategy":"validation","validationCode":"async function assertKnownFetchProvider(model) {\n  const res = await fetch(`${baseUrl}/dashboard/api/providers`);\n  const known = new Set((await res.json()).map((p) => p.id));\n  if (!known.has(model)) throw new Error(`Unknown provider for fetch: ${model}`);\n}","typeGuard":"function isRegisteredProvider(model, registryIds) {\n  return typeof model === 'string' && registryIds.includes(model.trim().toLowerCase());\n}","tryCatchPattern":"const res = await fetch(endpoint, { method: 'POST', body: JSON.stringify({ model, url }) });\nif (res.status === 400) {\n  const msg = await res.text();\n  if (msg.startsWith('Unknown provider:')) {\n    console.error(`Provider '${model}' not in registry - check dashboard provider list`);\n  }\n}","preventionTips":["Keep the client's model list in sync with the 9Router registry (export from the dashboard)","Trim and normalize provider names before sending; resolveProviderId handles case but not stray whitespace","After upgrading 9Router, re-check that provider ids used by automation still exist","Remember: the fetch endpoint requires fetch-capable providers; a chat-only name may still fail downstream"],"tags":["http-400","unknown-provider","provider-registry","web-fetch"],"backgroundTag":"unknown-provider","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}