{"record":{"id":"818346d1438b5c9b","repo":"abhigyanpatwari/GitNexus","slug":"unsupported-provider-config-as-any-provider","errorCode":null,"errorMessage":"Unsupported provider: ${(config as any).provider}","messagePattern":"Unsupported provider: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus-web/src/core/llm/agent.ts","lineNumber":348,"sourceCode":"      if (!deepseekConfig.apiKey || deepseekConfig.apiKey.trim() === '') {\n        throw new Error('DeepSeek API key is required but was not provided');\n      }\n\n      return new DeepSeekChatOpenAI({\n        apiKey: deepseekConfig.apiKey,\n        modelName: deepseekConfig.model,\n        temperature: deepseekConfig.temperature ?? 0.1,\n        maxTokens: deepseekConfig.maxTokens,\n        configuration: {\n          apiKey: deepseekConfig.apiKey,\n          baseURL: 'https://api.deepseek.com',\n        },\n        streaming: true,\n      });\n    }\n\n    default:\n      throw new Error(`Unsupported provider: ${(config as any).provider}`);\n  }\n};\n\n/**\n * Extract instance name from Azure endpoint URL\n * e.g., \"https://my-resource.openai.azure.com\" -> \"my-resource\"\n */\nconst extractInstanceName = (endpoint: string): string => {\n  try {\n    const url = new URL(endpoint);\n    const hostname = url.hostname;\n    // Extract the first part before .openai.azure.com. The trailing `$`\n    // anchor is required (CodeQL js/regex/missing-regexp-anchor): without\n    // it `evil.openai.azure.com.attacker.tld` would match.\n    const match = hostname.match(/^([^.]+)\\.openai\\.azure\\.com$/);\n    if (match) {\n      return match[1];\n    }","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/gitnexus-web/src/core/llm/agent.ts#L330-L366","documentation":"Thrown by createChatModel() in the default switch arm when config.provider does not match any supported provider. Supported values are: openai, azure-openai, gemini, anthropic, ollama, openrouter, minimax, glm, deepseek (see LLMProvider type). The offending value is echoed in the message to aid diagnosis. This is a type-safety backstop — TypeScript would normally prevent it, but runtime config from user input/storage can carry an unknown value.","triggerScenarios":"Calling createChatModel with a provider string outside the supported union, e.g. 'claude' (should be 'anthropic'), 'gpt' (should be 'openai'), 'azure' (should be 'azure-openai'), or a typo. Common when persisted settings from an older or newer version are loaded.","commonSituations":"A settings migration gap where a renamed provider id persists in localStorage; user-edited config with a typo; a frontend version skew between the persisted settings shape and the current provider list.","solutions":["Set config.provider to one of: openai, azure-openai, gemini, anthropic, ollama, openrouter, minimax, glm, deepseek","Check for typos — common ones: 'claude'→'anthropic', 'azure'→'azure-openai', 'gpt'→'openai'","Clear persisted provider settings and re-select from the UI if a version skew corrupted the stored value","If adding a new provider, add a case arm to the switch in createChatModel and extend the LLMProvider type"],"exampleFix":"// before — wrong provider id\ncreateChatModel({ provider: 'claude', apiKey: 'k', model: 'x' }); // throws\n\n// after — correct id\ncreateChatModel({ provider: 'anthropic', apiKey: 'k', model: 'claude-3-5-sonnet-20241022' });","handlingStrategy":"type-guard","validationCode":"import type { LLMProvider } from '../core/llm/types.js';\nconst SUPPORTED: readonly LLMProvider[] = ['openai','azure-openai','gemini','anthropic','ollama','openrouter','minimax','glm','deepseek'];\nfunction isSupportedProvider(p: string): p is LLMProvider {\n  return (SUPPORTED as readonly string[]).includes(p);\n}\nif (!isSupportedProvider(cfg.provider)) {\n  throw new Error(`Unknown provider '${cfg.provider}'. Supported: ${SUPPORTED.join(', ')}`);\n}","typeGuard":"import type { LLMProvider } from '../core/llm/types.js';\nfunction isLLMProvider(p: unknown): p is LLMProvider {\n  return typeof p === 'string' && ['openai','azure-openai','gemini','anthropic','ollama','openrouter','minimax','glm','deepseek'].includes(p);\n}","tryCatchPattern":"try {\n  createChatModel(cfg);\n} catch (e) {\n  if (e instanceof Error && /Unsupported provider/.test(e.message)) {\n    // show user the supported list, default to a working provider\n    cfg.provider = 'ollama';\n    return createChatModel(cfg);\n  }\n  throw e;\n}","preventionTips":["Constrain the provider field to the LLMProvider union at the type layer so invalid values can't persist","When renaming/adding a provider, migrate persisted settings (localStorage) to avoid stale ids","Validate the provider id against the supported list before constructing the model","Common alias typos: 'claude'→'anthropic', 'azure'→'azure-openai', 'gpt'→'openai'"],"tags":["llm","config","provider","validation"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}