decolua/9router · error

Unknown provider: ${providerInput}

Error message

Unknown provider: ${providerInput}

What it means

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.

Source

Thrown at src/sse/handlers/fetch.js:120

      log,
      comboName: providerInput,
      comboStrategy,
      comboStickyLimit
    });
  }

  return handleSingleProviderFetch(body, providerInput, request, apiKey, settings);
}

async function handleSingleProviderFetch(body, providerInput, request, apiKey, settings) {
  const targetUrl = body.url;
  const format = body.format;
  const maxCharacters = body.max_characters;
  const providerId = resolveProviderId(providerInput);
  const resolvedProvider = AI_PROVIDERS[providerId];

  if (!resolvedProvider) {
    log.warn("FETCH", "Unknown provider", { provider: providerInput });
    return errorResponse(HTTP_STATUS.BAD_REQUEST, `Unknown provider: ${providerInput}`);
  }

  const providerConfig = resolvedProvider.fetchConfig;
  if (!providerConfig) {
    log.warn("FETCH", "Provider does not support web fetch", { provider: providerId });
    return errorResponse(HTTP_STATUS.BAD_REQUEST, `Provider ${providerId} does not support web fetch`);
  }

  if (providerInput !== providerId) {
    log.info("ROUTING", `${providerInput} → ${providerId}`);
  } else {
    log.info("ROUTING", `Provider: ${providerId}`);
  }

  // No-auth fetch path (kept for parity though no current fetch provider sets noAuth)
  if (resolvedProvider.noAuth) {
    log.info("AUTH", `\x1b[32m${providerId} no-auth mode\x1b[0m`);

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Check the spelling against the provider list shown in the 9Router dashboard providers page
  2. Use the exact provider/model id as registered in open-sse/providers/registry (resolveProviderId handles case/alias, but not arbitrary names)
  3. If the provider exists for chat but not fetch, verify it has a fetchConfig in the registry - only fetch-capable providers resolve here
  4. Update the client's model list after upgrading 9Router (registry changes between versions)

Example fix

// before
{ model: 'jina reader' }
// after
{ model: 'jina' }  // exact registered provider id
Defensive patterns

Strategy: validation

Validate before calling

async function assertKnownFetchProvider(model) {
  const res = await fetch(`${baseUrl}/dashboard/api/providers`);
  const known = new Set((await res.json()).map((p) => p.id));
  if (!known.has(model)) throw new Error(`Unknown provider for fetch: ${model}`);
}

Type guard

function isRegisteredProvider(model, registryIds) {
  return typeof model === 'string' && registryIds.includes(model.trim().toLowerCase());
}

Try / catch

const res = await fetch(endpoint, { method: 'POST', body: JSON.stringify({ model, url }) });
if (res.status === 400) {
  const msg = await res.text();
  if (msg.startsWith('Unknown provider:')) {
    console.error(`Provider '${model}' not in registry - check dashboard provider list`);
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/1ed560582b7fdfdd. Report an issue: GitHub.