Mintplex-Labs/anything-llm · error · RetryError

error.message

Error message

error.message

What it means

OpenAIProvider.stream() (the Responses-API path) catches request failures and rethrows OpenAI RateLimitError, InternalServerError, or any APIError as aibitat's RetryError carrying only the original message; AuthenticationError is rethrown unwrapped; other errors propagate. RetryError is the engine's retryable marker, but note the wrap is broad: BadRequestError (400 — e.g. an invalid tool schema or unsupported parameter for the Responses API) also extends APIError, so a deterministic 400 is labeled 'retryable' even though retrying cannot succeed. The client is built from config.options, defaulting apiKey to process.env.OPEN_AI_KEY.

Solutions

  1. Look at the leading status in the RetryError message: 400 means your payload/schema is wrong — fix it, do not retry; 429/5xx are safe to retry
  2. For 400s, validate every function's JSON schema (parameters objects must declare type/properties) before the agent runs
  3. For 429s, raise org rate limits, reduce tool-call rounds, or space requests; then re-run the chat
  4. Confirm the model id in agent config exists for your OPEN_AI_KEY org (404 wraps as RetryError here)

Example fix

// before: tool schema the Responses API rejects with 400
const functions = [{ name: "lookup", parameters: { query: { type: "string" } } }];

// after: valid JSON Schema object
const functions = [{
  name: "lookup",
  parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] }
}];
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: key present + tool schemas are valid JSON Schema before streaming
if (!process.env.OPEN_AI_KEY) throw new Error("OPEN_AI_KEY not set");
for (const fn of functions) {
  if (!fn.parameters || fn.parameters.type !== "object") {
    throw new Error(`Tool '${fn.name}' parameters must be a JSON Schema object`);
  }
}

Type guard

const { RetryError } = require("./server/utils/agents/aibitat/error.js");
const isRetryError = (e) => e instanceof RetryError;
const isDeterministic400 = (e) => isRetryError(e) && /^400|Bad Request/i.test(String(e.message)); // retrying cannot fix this

Try / catch

try {
  return await provider.stream(messages, functions);
} catch (error) {
  if (error instanceof OpenAI.AuthenticationError) throw error;
  if (isDeterministic400(error)) throw new Error(`Fix the request/tool schema: ${error.message}`);
  if (error instanceof RetryError && /429|5\d\d/.test(error.message)) return withBackoff(retryStream, { tries: 3 });
  throw error;
}

Prevention

When it happens

Trigger: Responses API call (client.responses.create after #formatToResponsesInput) returning 429 (OpenAI org/token-per-minute limits), 5xx platform incidents, 400 for malformed tool definitions or message mapping (e.g. a function message missing originalFunctionCall is skipped, but schema violations 400), or 404 when the configured model id (default gpt-4.1-nano) is unavailable to the org.

Common situations: Agent tool loops bursting past TPM/RPM caps; custom tool schemas with wrong JSON structure that the Responses API rejects with 400; org not entitled to the default model; expired OPEN_AI_KEY surfacing as an unwrapped AuthenticationError instead.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18). Data as JSON: /api/errors/7c0d33e7836fd0eb. Report an issue: GitHub.

Appendix: source

Thrown at server/utils/agents/aibitat/providers/openai.js:246

          uuid: msgUUID,
        };
      }

      return {
        textResponse: completion.content,
        functionCall: null,
        cost: this.getCost(),
        uuid: msgUUID,
      };
    } catch (error) {
      if (error instanceof OpenAI.AuthenticationError) throw error;

      if (
        error instanceof OpenAI.RateLimitError ||
        error instanceof OpenAI.InternalServerError ||
        error instanceof OpenAI.APIError
      ) {
        throw new RetryError(error.message);
      }

      throw error;
    }
  }

  /**
   * Create a completion based on the received messages.
   *
   * @param messages A list of messages to send to the OpenAI API.
   * @param functions
   * @returns The completion.
   */
  async complete(messages, functions = []) {
    this.providerLog("OpenAI.complete - will process this chat completion.");
    this.resetUsage();

    try {

View on GitHub (pinned to 3aec848f28)