Mintplex-Labs/anything-llm · error · Error

Invalid response body returned from GiteeAI: ${JSON.stringif

Error message

Invalid response body returned from GiteeAI: ${JSON.stringify(result.output)}

What it means

Thrown after a successful HTTP call when the response body is structurally invalid: result.output has no `choices` property, or the choices array is empty. Unlike the catch wrapper, this means the server answered without throwing but the body is not a usable OpenAI-format completion. The full response is JSON-stringified into the message for debugging.

Source

Thrown at server/utils/AiProviders/giteeai/index.js:139

  async getChatCompletion(messages = null, { temperature = 0.7 }) {
    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
    )
      throw new Error(
        `Invalid response body returned from GiteeAI: ${JSON.stringify(result.output)}`
      );

    return {
      textResponse: this.#parseReasoningFromResponse(result.output.choices[0]),
      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 / result.duration,
        duration: result.duration,
        model: this.model,
        provider: this.className,
        timestamp: new Date(),
      },
    };
  }

View on GitHub (pinned to 526360e320)

Solutions

  1. Read the JSON.stringify(result.output) embedded in the message — it shows exactly what Gitee returned
  2. If it contains an `error` field, address that cause (content policy, model unavailable)
  3. Retry once in case of a transient gateway/partial response
  4. Check Gitee AI status/changelog for response-schema changes

Example fix

// before
if (!result?.output?.hasOwnProperty('choices') || result?.output?.choices?.length === 0)
  throw new Error(`Invalid response body returned from GiteeAI: ${JSON.stringify(result.output)}`);

// after (surface a structured, type-safe error instead of a stringly one)
if (!result?.output?.choices?.length)
  throw new GiteeResponseError('No choices in GiteeAI response', result.output);
Defensive patterns

Strategy: type-guard

Type guard

function isOpenAiCompletion(payload) {
  return payload != null
    && Array.isArray(payload.choices)
    && payload.choices.length > 0
    && payload.choices[0]?.message != null;
}

Try / catch

const result = await llm.getChatCompletion(messages, { temperature }).catch(async (e) => {
  if (/Invalid response body returned from GiteeAI/.test(e.message)) {
    // inspect the stringified body in the message, classify (content filter vs outage)
    if (/content_filter|safety/i.test(e.message)) throw new ContentFilterError(e.message);
    throw new UpstreamFormatError(e.message);
  }
  throw e;
});

Prevention

When it happens

Trigger: Gitee AI returns 200 with a body missing `choices` — e.g. an error object {error: ...}, an HTML error page parsed as text, a content-filter block with no choices, or a schema change on Gitee's side. The `.hasOwnProperty('choices')` / `choices.length === 0` check then trips.

Common situations: Gitee AI content policy rejecting the prompt (returns an object without choices); upstream model crashed and Gitee returned a status envelope; partial/gateway response; API version drift where the response shape changed.

Related errors


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