{"record":{"id":"1e9cfa288f45b065","repo":"Mintplex-Labs/anything-llm","slug":"unsupported-provider-json-stringify-provider-f","errorCode":null,"errorMessage":"Unsupported provider ${JSON.stringify(provider)} for this task.","messagePattern":"Unsupported provider (.+?) for this task\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"server/utils/agents/aibitat/providers/ai-provider.js","lineNumber":499,"sourceCode":"        });\n      case \"lemonade\":\n        return new ChatOpenAI({\n          configuration: {\n            baseURL: process.env.LEMONADE_LLM_BASE_PATH,\n          },\n          apiKey: process.env.LEMONADE_LLM_API_KEY || null,\n          ...config,\n        });\n      case \"omlx\":\n        return new ChatOpenAI({\n          configuration: {\n            baseURL: parseOMLXBasePath(process.env.OMLX_LLM_BASE_PATH),\n          },\n          apiKey: process.env.OMLX_LLM_API_KEY || null,\n          ...config,\n        });\n      default:\n        throw new Error(\n          `Unsupported provider ${JSON.stringify(provider)} for this task.`\n        );\n    }\n  }\n\n  /**\n   * Get the context limit for a provider/model combination using static method in AIProvider class.\n   * @param {string} provider\n   * @param {string} modelName\n   * @returns {number}\n   */\n  static contextLimit(provider = \"openai\", modelName) {\n    if (typeof provider !== \"string\") {\n      console.log(\n        `\\x1b[43m\\x1b[30m[.contextLimit warning] A non-string provider for .contextLimit was given — Returning fallback context limit of 8000.\\x1b[0m\\n\\x1b[43m\\x1b[30mThis is a bug and should be reported so that context windows are properly managed by AnythingLLM.\\x1b[0m`\n      );\n      console.trace();\n      return 8_000;","sourceCodeStart":481,"sourceCodeEnd":517,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/server/utils/agents/aibitat/providers/ai-provider.js#L481-L517","documentation":"Thrown by the LangChain `ChatOpenAI` factory switch in ai-provider.js when the `provider` argument matches no case (openai, azure, anthropic, localai, litellm, foundry, docker-model-runner, lemonade, omlx, etc.). It is a hard `default:` throw with no fallback, so a typo or a slug valid elsewhere in the app but unregistered in this switch lands here. The message echoes `JSON.stringify(provider)` so whitespace and case are visible in the diagnostic.","triggerScenarios":"Caller passes a provider slug valid for the main provider registry but not wired into this LangChain factory; typo in config/env (e.g. \"docke-model-runner\"); a custom provider was added to the UI picker but the case here was forgotten; null/undefined provider passed through from an unvalidated API field.","commonSituations":"New provider added to the picker without a matching case in this factory; a stored workspace setting references a provider the current build does not know (e.g. after a downgrade); provider string sourced from a request body or DB row that was never allow-listed.","solutions":["Compare the exact string in the error (it is JSON-stringified, so quotes/case are visible) against the case labels near ai-provider.js:499.","Add the missing `case` to the switch if this provider is intended to be supported by this factory.","Fix the upstream caller — it may be passing the display name instead of the canonical slug.","If the value came from a stored workspace setting, migrate or reset the setting to a known slug.","Validate the provider against an allow-list before invoking this factory."],"exampleFix":"// before\nasync function buildChat(provider, config) {\n  switch (provider) {\n    // ... existing cases ...\n    default:\n      throw new Error(`Unsupported provider ${JSON.stringify(provider)} for this task.`);\n  }\n}\n\n// after — validate at the trust boundary, not inside the factory\nconst KNOWN = new Set([\"openai\",\"azure\",\"anthropic\",\"localai\",\"litellm\",\"foundry\",\"docker-model-runner\",\"lemonade\",\"omlx\"]);\nfunction assertKnownProvider(provider) {\n  if (!KNOWN.has(provider))\n    throw new Error(`Unsupported provider ${JSON.stringify(provider)} for this task.`);\n}\n// call assertKnownProvider(provider) before buildChat","handlingStrategy":"validation","validationCode":"// Allow-list the provider at the trust boundary, not inside the factory.\nconst SUPPORTED_PROVIDERS = new Set([\n  'openai','azure','anthropic','localai','litellm','foundry',\n  'docker-model-runner','lemonade','omlx' /* keep in sync with the switch */\n]);\nfunction assertSupportedProvider(provider) {\n  if (!SUPPORTED_PROVIDERS.has(provider))\n    throw new Error(`Unsupported provider ${JSON.stringify(provider)} for this task.`);\n}","typeGuard":"function isSupportedProvider(provider) {\n  return typeof provider === 'string' && SUPPORTED_PROVIDERS.has(provider);\n}","tryCatchPattern":"// Validate before constructing; let the error bubble as a 400 to the caller.\nassertSupportedProvider(provider);\nreturn buildChat(provider, config);","preventionTips":["Keep the allow-list and the switch in sync — a new case must update both.","Validate provider strings coming from request bodies / DB rows, never trust them blindly.","Use canonical slugs everywhere; never pass display names to the factory.","Add a unit test that iterates the picker's provider list against the allow-list."],"tags":["provider","config","switch-default","langchain","validation"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}