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
- 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
- For 400s, validate every function's JSON schema (parameters objects must declare type/properties) before the agent runs
- For 429s, raise org rate limits, reduce tool-call rounds, or space requests; then re-run the chat
- 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
- Validate every tool's parameters as a real JSON Schema object (type: "object" + properties) before the agent runs — 400s get wrapped as 'retryable' here but are not
- Monitor org TPM/RPM in the OpenAI dashboard; agent tool loops burst fast
- Confirm the model id (default gpt-4.1-nano) is available to your org before pinning it
- Treat 401 AuthenticationError (unwrapped) as a key problem, never a retry case
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)