{"record":{"id":"d50e745cd5220d47","repo":"Mintplex-Labs/anything-llm","slug":"e-message","errorCode":null,"errorMessage":"${e.message}","messagePattern":"\\$\\{e\\.message\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/utils/AiProviders/apipie/index.js","lineNumber":204,"sourceCode":"      },\n    ];\n  }\n\n  async getChatCompletion(messages = null, { temperature = 0.7 }) {\n    if (!(await this.isValidChatCompletionModel(this.model)))\n      throw new Error(\n        `ApiPie 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:\n          (result.output.usage?.completion_tokens || 0) / result.duration,\n        duration: result.duration,","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/server/utils/AiProviders/apipie/index.js#L186-L222","documentation":"Re-throws the raw `e.message` from the OpenAI SDK's `chat.completions.create` promise rejection inside ApiPieLLM.getChatCompletion. Unlike the model-validity guard, this fires only after a real network round-trip to https://apipie.ai/v1, so the message reflects ApiPie's HTTP-level response (status text, body error).","triggerScenarios":"ApiPie upstream returns an error: 401 bad key, 402/429 quota or rate limit, 400 malformed messages, 404 model not deployed, or the SDK throws on a transport error (timeout, reset). The .catch strips context and surfaces only e.message.","commonSituations":"Out of ApiPie credits; rate-limited under bursty traffic; key revoked; sent an unsupported message role or malformed content; ApiPie brief outage; network blip between server and apipie.ai.","solutions":["Inspect e.message — it usually contains the HTTP status and ApiPie error text; address the named cause (quota, auth, payload).","For quota/rate-limit (402/429), top up credits or throttle concurrency and retry with backoff.","For auth (401), confirm APIPIE_LLM_API_KEY is current in .env and restart.","For payload errors, validate message shape/roles before calling; for transport errors, retry once then surface to the user."],"exampleFix":"// before\n.catch((e) => {\n  throw new Error(e.message);\n})\n\n// after - preserve status for caller retry logic\n.catch((e) => {\n  const err = new Error(e.message);\n  err.status = e.status ?? e.response?.status;\n  err.retryable = [429, 500, 502, 503, 504].includes(err.status);\n  throw err;\n})","handlingStrategy":"try-catch","validationCode":"// Cheap checks before the network call\nif (!this.model) throw new Error(\"No ApiPie model selected.\");\nif (!Array.isArray(messages) || messages.length === 0)\n  throw new Error(\"Messages must be a non-empty array.\");\n// Auth/quota can only be truly detected by the call itself.","typeGuard":"/** @param {unknown} e @returns {boolean} */\nfunction isOpenAiCompatError(e) {\n  return e != null && typeof e === \"object\" &&\n    typeof e.message === \"string\" &&\n    (typeof e.status === \"number\" || typeof e.response?.status === \"number\");\n}","tryCatchPattern":"try {\n  const res = await llm.getChatCompletion(messages, { temperature });\n} catch (e) {\n  const status = e.status ?? e.response?.status;\n  if (status === 401) await refreshApiPieKey();\n  else if (status === 429 || status === 402) await backoffRetry(fn);\n  else if (status >= 500) await backoffRetry(fn);\n  else throw e;\n}","preventionTips":["Preserve the upstream status code on rethrow so callers can branch on it.","Distinguish quota/rate-limit (429/402) from auth (401) and payload (400) in recovery logic.","Add a bounded retry policy only for idempotent, transient failures.","Log the full SDK error object once at the boundary for post-mortem."],"tags":["network","api","apipie","try-catch","runtime"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}