{"record":{"id":"421c0e94ee780540","repo":"janhq/jan","slug":"unexpected-error-while-fetching-models-from-prov","errorCode":null,"errorMessage":"Unexpected error while fetching models from ${provider.provider}: ${error instanceof Error ? error.message : 'Unknown error'}","messagePattern":"Unexpected error while fetching models from (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web-app/src/services/providers/tauri.ts","lineNumber":278,"sourceCode":"\n      if (\n        error instanceof Error &&\n        structuredErrorPrefixes.some((prefix) =>\n          (error as Error).message.startsWith(prefix)\n        )\n      ) {\n        throw new Error(error.message)\n      }\n\n      // Provide helpful error message for any connection errors\n      if (error instanceof Error && error.message.includes('fetch')) {\n        throw new Error(\n          `Cannot connect to ${provider.provider} at ${provider.base_url}. Please check that the service is running and accessible.`\n        )\n      }\n\n      // Generic fallback\n      throw new Error(\n        `Unexpected error while fetching models from ${provider.provider}: ${error instanceof Error ? error.message : 'Unknown error'}`\n      )\n    }\n  }\n\n  async updateSettings(\n    providerName: string,\n    settings: ProviderSetting[]\n  ): Promise<void> {\n    try {\n      // API keys are persisted to the OS keyring only (via\n      // register_provider_config), never to the extension's settings.json.\n      // Blank the key entries at this single chokepoint regardless of caller.\n      const isSecretKey = (key: string) =>\n        key === 'api-key' || key === API_KEY_FALLBACKS_SETTING_KEY\n      return ExtensionManager.getInstance()\n        .getEngine(providerName)\n        ?.updateSettings(","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/web-app/src/services/providers/tauri.ts#L260-L296","documentation":"The catch-all fallback in getModels for any error that is neither a structured provider error (162) nor a connection-style failure (163). Typically wraps JSON parse failures, unexpected thrown types, or runtime errors inside the data-shaping branches. It preserves the original message so it isn't lost.","triggerScenarios":"response.json() throws on an invalid/non-JSON body; an exception inside the .map/.filter shaping branches; a non-Error value thrown somewhere in the try block; the provider returns 200 OK with an HTML error page.","commonSituations":"Provider returns 200 with a non-JSON body (HTML error page, plain text); provider returns an unexpected data shape that breaks the mapping logic; a regression in the parsing branches throws a TypeError.","solutions":["Inspect the embedded original error message - it pinpoints the real failure (e.g., 'Unexpected token < in JSON').","Reproduce with curl to inspect the raw body and Content-Type of /models.","If JSON parsing fails, the provider may be returning HTML with a 200 - verify the endpoint and Content-Type.","Add a Content-Type check before calling response.json()."],"exampleFix":"// before: 200 OK with HTML body -> response.json() throws -> generic fallback\nconst data = await response.json()\n// after: guard Content-Type before parsing\nconst ct = response.headers.get('content-type') ?? ''\nif (!ct.includes('application/json')) {\n  throw new Error(`Expected JSON from ${provider.provider}/models but got '${ct}'`)\n}\nconst data = await response.json()","handlingStrategy":"try-catch","validationCode":"async function safeJson(res: Response): Promise<unknown> {\n  const ct = res.headers.get('content-type') ?? ''\n  if (!ct.includes('application/json')) throw new Error(`Non-JSON response: ${ct}`)\n  return res.json()\n}","typeGuard":"function isJsonContentType(res: Response): boolean {\n  return (res.headers.get('content-type') ?? '').includes('application/json')\n}","tryCatchPattern":"try {\n  await provider.getModels(p)\n} catch (e) {\n  // Anything not matching structured/connection prefixes lands here\n  logUnexpected(e)\n  showGenericError()\n}","preventionTips":["Validate Content-Type before JSON parsing.","Report these as bugs - they indicate an unhandled path.","Log the raw response body on parse failure for diagnosis."],"tags":["unexpected","json-parse","fallback","provider-api","models"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}