Mintplex-Labs/anything-llm · error · Error

${e.message}

Error message

${e.message}

What it means

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).

Source

Thrown at server/utils/AiProviders/apipie/index.js:204

      },
    ];
  }

  async getChatCompletion(messages = null, { temperature = 0.7 }) {
    if (!(await this.isValidChatCompletionModel(this.model)))
      throw new Error(
        `ApiPie chat: ${this.model} is not valid for chat completion!`
      );

    const result = await LLMPerformanceMonitor.measureAsyncFunction(
      this.openai.chat.completions
        .create({
          model: this.model,
          messages,
          temperature,
        })
        .catch((e) => {
          throw new Error(e.message);
        })
    );

    if (
      !result.output.hasOwnProperty("choices") ||
      result.output.choices.length === 0
    )
      return null;

    return {
      textResponse: result.output.choices[0].message.content,
      metrics: {
        prompt_tokens: result.output.usage?.prompt_tokens || 0,
        completion_tokens: result.output.usage?.completion_tokens || 0,
        total_tokens: result.output.usage?.total_tokens || 0,
        outputTps:
          (result.output.usage?.completion_tokens || 0) / result.duration,
        duration: result.duration,

View on GitHub (pinned to 526360e320)

Solutions

  1. Inspect e.message — it usually contains the HTTP status and ApiPie error text; address the named cause (quota, auth, payload).
  2. For quota/rate-limit (402/429), top up credits or throttle concurrency and retry with backoff.
  3. For auth (401), confirm APIPIE_LLM_API_KEY is current in .env and restart.
  4. For payload errors, validate message shape/roles before calling; for transport errors, retry once then surface to the user.

Example fix

// before
.catch((e) => {
  throw new Error(e.message);
})

// after - preserve status for caller retry logic
.catch((e) => {
  const err = new Error(e.message);
  err.status = e.status ?? e.response?.status;
  err.retryable = [429, 500, 502, 503, 504].includes(err.status);
  throw err;
})
Defensive patterns

Strategy: try-catch

Validate before calling

// Cheap checks before the network call
if (!this.model) throw new Error("No ApiPie model selected.");
if (!Array.isArray(messages) || messages.length === 0)
  throw new Error("Messages must be a non-empty array.");
// Auth/quota can only be truly detected by the call itself.

Type guard

/** @param {unknown} e @returns {boolean} */
function isOpenAiCompatError(e) {
  return e != null && typeof e === "object" &&
    typeof e.message === "string" &&
    (typeof e.status === "number" || typeof e.response?.status === "number");
}

Try / catch

try {
  const res = await llm.getChatCompletion(messages, { temperature });
} catch (e) {
  const status = e.status ?? e.response?.status;
  if (status === 401) await refreshApiPieKey();
  else if (status === 429 || status === 402) await backoffRetry(fn);
  else if (status >= 500) await backoffRetry(fn);
  else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13). Data as JSON: /api/errors/d50e745cd5220d47. Report an issue: GitHub.