{"record":{"id":"7c0d33e7836fd0eb","repo":"Mintplex-Labs/anything-llm","slug":"error-message-7c0d33","errorCode":null,"errorMessage":"error.message","messagePattern":"error\\.message","errorType":"exception","errorClass":"RetryError","httpStatus":null,"severity":"error","filePath":"server/utils/agents/aibitat/providers/openai.js","lineNumber":246,"sourceCode":"          uuid: msgUUID,\n        };\n      }\n\n      return {\n        textResponse: completion.content,\n        functionCall: null,\n        cost: this.getCost(),\n        uuid: msgUUID,\n      };\n    } catch (error) {\n      if (error instanceof OpenAI.AuthenticationError) throw error;\n\n      if (\n        error instanceof OpenAI.RateLimitError ||\n        error instanceof OpenAI.InternalServerError ||\n        error instanceof OpenAI.APIError\n      ) {\n        throw new RetryError(error.message);\n      }\n\n      throw error;\n    }\n  }\n\n  /**\n   * Create a completion based on the received messages.\n   *\n   * @param messages A list of messages to send to the OpenAI API.\n   * @param functions\n   * @returns The completion.\n   */\n  async complete(messages, functions = []) {\n    this.providerLog(\"OpenAI.complete - will process this chat completion.\");\n    this.resetUsage();\n\n    try {","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/utils/agents/aibitat/providers/openai.js#L228-L264","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before: tool schema the Responses API rejects with 400\nconst functions = [{ name: \"lookup\", parameters: { query: { type: \"string\" } } }];\n\n// after: valid JSON Schema object\nconst functions = [{\n  name: \"lookup\",\n  parameters: { type: \"object\", properties: { query: { type: \"string\" } }, required: [\"query\"] }\n}];","handlingStrategy":"try-catch","validationCode":"// Pre-flight: key present + tool schemas are valid JSON Schema before streaming\nif (!process.env.OPEN_AI_KEY) throw new Error(\"OPEN_AI_KEY not set\");\nfor (const fn of functions) {\n  if (!fn.parameters || fn.parameters.type !== \"object\") {\n    throw new Error(`Tool '${fn.name}' parameters must be a JSON Schema object`);\n  }\n}","typeGuard":"const { RetryError } = require(\"./server/utils/agents/aibitat/error.js\");\nconst isRetryError = (e) => e instanceof RetryError;\nconst isDeterministic400 = (e) => isRetryError(e) && /^400|Bad Request/i.test(String(e.message)); // retrying cannot fix this","tryCatchPattern":"try {\n  return await provider.stream(messages, functions);\n} catch (error) {\n  if (error instanceof OpenAI.AuthenticationError) throw error;\n  if (isDeterministic400(error)) throw new Error(`Fix the request/tool schema: ${error.message}`);\n  if (error instanceof RetryError && /429|5\\d\\d/.test(error.message)) return withBackoff(retryStream, { tries: 3 });\n  throw error;\n}","preventionTips":["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"],"tags":["llm-provider","openai","responses-api","retry-error","rate-limit","streaming"],"backgroundTag":"openai-api-error","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}