flipped-aurora/gin-vue-admin · error

上游大模型服务返回非 2xx: status=%d content-type=%s body=%s

Error message

上游大模型服务返回非 2xx: status=%d content-type=%s body=%s

What it means

After reading the body, LLMAuto checks the HTTP status and rejects anything outside 200–299, embedding status, Content-Type, and a truncated body preview. The upstream LLM service answered, but with an HTTP-level failure (auth, rate limit, bad request, server error).

Source

Thrown at server/service/system/auto_code_llm.go:45

		http.MethodPost,
		nil,
		nil,
		llm,
	)
	if err != nil {
		return nil, fmt.Errorf("调用上游大模型服务失败: %w", err)
	}
	defer res.Body.Close()

	body, err := io.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("读取大模型响应失败: %w", err)
	}

	bodyPreview := previewResponseBody(body)
	contentType := res.Header.Get("Content-Type")
	if res.StatusCode < 200 || res.StatusCode >= 300 {
		return nil, fmt.Errorf("上游大模型服务返回非 2xx: status=%d content-type=%s body=%s", res.StatusCode, contentType, bodyPreview)
	}

	var resStruct commonResp.Response
	if err = json.Unmarshal(body, &resStruct); err != nil {
		return nil, fmt.Errorf("解析大模型响应失败: status=%d content-type=%s body=%s err=%w", res.StatusCode, contentType, bodyPreview, err)
	}

	if resStruct.Code != commonResp.SUCCESS {
		return nil, fmt.Errorf("大模型服务返回业务错误: code=%d msg=%s body=%s", resStruct.Code, resStruct.Msg, bodyPreview)
	}

	return resStruct.Data, nil
}

func (s *AutoCodeService) LLMAutoStream(ctx context.Context, llm common.JSONMap) (*http.Response, error) {
	path, err := buildLLMAutoPath(llm)
	if err != nil {
		return nil, err

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Read the status and body preview in the error to identify the upstream cause (401→key, 429→quota, 400→payload)
  2. Fix the API key / model name / request payload in the llm config accordingly
  3. For 429, add backoff/retry respecting the provider's rate limits
  4. For 5xx, retry later or switch to a fallback provider/region

Example fix

// before: only generic wrap upstream, no status inspection
if err != nil { return nil, err }
// after: inspect status before treating response as success
if res.StatusCode == http.StatusUnauthorized {
    return nil, fmt.Errorf("LLM 鉴权失败,请检查 API Key")
}
if res.StatusCode >= 500 {
    return nil, fmt.Errorf("LLM 服务端错误,可稍后重试: status=%d", res.StatusCode)
}
Defensive patterns

Strategy: validation

Validate before calling

if res.StatusCode < 200 || res.StatusCode >= 300 {
    return fmt.Errorf("上游返回非 2xx: status=%d body=%s", res.StatusCode, previewResponseBody(body))
}

Try / catch

if err != nil {
    if strings.Contains(err.Error(), "status=429") {
        // backoff and retry respecting rate limit
    } else if strings.Contains(err.Error(), "status=401") {
        // refresh API key / surface auth config error to operator
    }
    return err
}

Prevention

When it happens

Trigger: Calling LLMAuto when the upstream returns 4xx/5xx — e.g. 401 for a bad/expired API key, 429 rate limit, 400 for an invalid model name or malformed payload, 502/503 for upstream outages.

Common situations: Rotated or unset API keys, exhausted provider quota, wrong model identifier after a provider version change, payload fields not accepted by the provider, provider regional outage.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/c46eead0b5fd94e6. Report an issue: GitHub.