{"record":{"id":"7f90666aa89fe54a","repo":"decolua/9router","slug":"invalid-model-format","errorCode":null,"errorMessage":"Invalid model format","messagePattern":"Invalid model format","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"src/sse/handlers/chat.js","lineNumber":212,"sourceCode":"        });\n      }\n\n      const comboStickyLimit = chatSettings.comboStickyRoundRobinLimit;\n      log.info(\"CHAT\", `Combo \"${modelStr}\" with ${augmentedModels.length} models (strategy: ${comboStrategy}, sticky: ${comboStickyLimit})`);\n      return handleComboChat({\n        body,\n        models: augmentedModels,\n        handleSingleModel: withCapacityAdapterStripping(\n          (b, m) => handleSingleModelChat(b, m, clientRawRequest, request, apiKey),\n          adapterAdded\n        ),\n        log,\n        comboName: modelStr,\n        comboStrategy,\n        comboStickyLimit\n      });\n    }\n    log.warn(\"CHAT\", \"Invalid model format\", { model: modelStr });\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, \"Invalid model format\");\n  }\n\n  const { provider, model } = modelInfo;\n\n  // Routing shown in the unified \"▶\" line (client model → provider/model)\n\n  // Extract userAgent from request\n  const userAgent = request?.headers?.get(\"user-agent\") || \"\";\n\n  // Try with available accounts (fallback on errors)\n  const excludeConnectionIds = new Set();\n  let lastError = null;\n  let lastStatus = null;\n\n  while (true) {\n    const credentials = await getProviderCredentials(provider, excludeConnectionIds, model);\n","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/sse/handlers/chat.js#L194-L230","documentation":"handleSingleModelChat resolved the requested model string via getModelInfo and got back no provider/model pair, meaning the string matches neither a registered provider/model nor a known combo. The handler returns 400 'Invalid model format'.","triggerScenarios":"POST /v1/chat/completions with model set to something that getModelInfo cannot parse: an unknown 'provider/model' prefix, a typo'd model name, or a model not present in the provider registry/config.","commonSituations":"Model name copied from upstream docs that 9Router doesn't register; renamed model after a provider updated their catalog; combo deleted in dashboard but still referenced by the client; wrong separator (e.g. 'openai:gpt-4o' instead of 'openai/gpt-4o'); client still pointing at a model from a previous router config.","solutions":["Check the 9Router dashboard's model list and use an exact registered model string (provider/model).","Fix typos and separators — the format must match what getModelInfo expects (provider/model or a combo name).","If the provider's model was renamed/added, update open-sse/config/providerModels.js or the provider registry, then restart.","If it should be a combo, recreate the combo in the dashboard with that name."],"exampleFix":"// before\n{ \"model\": \"GPT-4o-mini\" }\n\n// after\n{ \"model\": \"openai/gpt-4o-mini\" }","handlingStrategy":"validation","validationCode":"const KNOWN = new Set(['openai/gpt-4o', 'openai/gpt-4o-mini' /* fetch full list from dashboard API */]);\nif (!KNOWN.has(model)) throw new Error(`unknown model: ${model} — must be provider/model or a combo name`);","typeGuard":"function isProviderModel(s) {\n  return typeof s === 'string' && /^[a-z0-9_-]+\\/[\\w.:-]+$/i.test(s);\n}","tryCatchPattern":"const res = await fetch(url, opts);\nif (res.status === 400 && (await res.text()).includes('Invalid model format')) {\n  throw new Error(`Model \"${opts.body.model}\" is not registered in 9Router`);\n}","preventionTips":["Pull the live model list from the dashboard and validate against it at startup.","Centralize model strings in constants instead of inlining literals.","After provider catalog updates, verify model names still exist in 9Router config.","Use the provider/model separator exactly as the dashboard shows."],"tags":["http","bad-request","model","validation"],"backgroundTag":"unknown-model","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}