{"record":{"id":"423743ffd8137b63","repo":"Mintplex-Labs/anything-llm","slug":"e-message-423743","errorCode":null,"errorMessage":"e.message","messagePattern":"e\\.message","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/utils/AiProviders/novita/index.js","lineNumber":236,"sourceCode":"      },\n    ];\n  }\n\n  async getChatCompletion(messages = null, { temperature = 0.7 }) {\n    if (!(await this.isValidChatCompletionModel(this.model)))\n      throw new Error(\n        `Novita chat: ${this.model} is not valid for chat completion!`\n      );\n\n    const result = await LLMPerformanceMonitor.measureAsyncFunction(\n      this.openai.chat.completions\n        .create({\n          model: this.model,\n          messages,\n          temperature,\n        })\n        .catch((e) => {\n          throw new Error(e.message);\n        })\n    );\n\n    if (\n      !result.output.hasOwnProperty(\"choices\") ||\n      result.output.choices.length === 0\n    )\n      return null;\n\n    return {\n      textResponse: result.output.choices[0].message.content,\n      metrics: {\n        prompt_tokens: result.output.usage.prompt_tokens || 0,\n        completion_tokens: result.output.usage.completion_tokens || 0,\n        total_tokens: result.output.usage.total_tokens || 0,\n        outputTps: result.output.usage.completion_tokens / result.duration,\n        duration: result.duration,\n        model: this.model,","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/server/utils/AiProviders/novita/index.js#L218-L254","documentation":"Identical re-wrap anti-pattern in Novita's getChatCompletion: .catch flattens any upstream Novita API error to Error(e.message), discarding status/type. On a choices-less successful response Novita (like Mistral) returns null rather than throwing.","triggerScenarios":"Any upstream failure from the Novita chat completion call: 401, 429, 400, timeout, or 5xx — surfaced only as the message string. Note the 3000ms defaultTimeout can also produce timeout errors here.","commonSituations":"Invalid Novita key; rate/quota limits; the 3s defaultTimeout firing on slow models (timeout surfaces as an error message here); transient outage.","solutions":["Inspect the message for the upstream cause.","If timeout-like, raise defaultTimeout or choose a faster model.","If auth/quota text, verify NOVITA_LLM_API_KEY and plan limits.","Retry with backoff for transient text."],"exampleFix":"// before\ndefaultTimeout = 3_000;  // too low for slow models\n.catch((e) => { throw new Error(e.message); })\n\n// after\ndefaultTimeout = 30_000;\n.catch((e) => {\n  const err = new Error(`Novita chat failed (${e?.status}): ${e.message}`);\n  err.cause = e; err.status = e?.status;\n  throw err;\n})","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await llm.getChatCompletion(messages, { temperature });\n} catch (e) {\n  const msg = e.message || '';\n  if (/timeout|etimedout|econnaborted/i.test(msg)) { /* raise defaultTimeout or pick a faster model */ }\n  else if (/429|rate/i.test(msg)) { /* backoff */ }\n  else if (/401|api key/i.test(msg)) { /* rotate key */ }\n}","preventionTips":["The 3000ms defaultTimeout is low for slow Novita models — raise it for production.","Patch the catch to preserve e.status/e.cause.","Add backoff for transient upstream errors."],"tags":["novita","error-handling","openai-client","anti-pattern","timeout"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}