flipped-aurora/gin-vue-admin · critical
调用上游大模型失败: %w
Error message
调用上游大模型失败: %w
What it means
streamLLMAsSSE in server/api/v1/system/sys_auto_code_sse.go first calls the service method LLMAutoStream(ctx, llm), which performs the outbound HTTP request to the upstream LLM and returns the *http.Response. Any error from that call (DNS failure, connection refused/refused TLS, request-context cancellation, client construction failure) is wrapped as fmt.Errorf("调用上游大模型失败: %w", err) — 'failed to call upstream LLM'. This error is thrown before any status-code check; it means the request itself never completed.
Source
Thrown at server/api/v1/system/sys_auto_code_sse.go:54
llm = common.JSONMap{}
}
llm["response_mode"] = "streaming"
logger.WithCtx(c.Request.Context()).Mod("biz").Field("mode", llm["mode"]).Info("LLMAutoSSE 收到请求")
if err := autoApi.streamLLMAsSSE(c, llm); err != nil {
logger.WithCtx(c.Request.Context()).Mod("biz").Err(err).Error("大模型 SSE 代理失败!")
if c.Writer.Written() {
writeLLMStreamError(c, err)
return
}
response.FailWithMessage(err.Error(), c)
}
}
func (autoApi *AutoCodeApi) streamLLMAsSSE(c *gin.Context, llm common.JSONMap) error {
res, err := autoCodeService.LLMAutoStream(c.Request.Context(), llm)
if err != nil {
return fmt.Errorf("调用上游大模型失败: %w", err)
}
defer res.Body.Close()
if res.StatusCode < 200 || res.StatusCode >= 300 {
body, readErr := io.ReadAll(res.Body)
if readErr != nil {
return fmt.Errorf("上游大模型流式服务返回非 2xx: status=%d content-type=%s read-body-err=%w", res.StatusCode, res.Header.Get("Content-Type"), readErr)
}
return fmt.Errorf("上游大模型流式服务返回非 2xx: status=%d content-type=%s body=%s", res.StatusCode, res.Header.Get("Content-Type"), previewResponseBody(body))
}
ct := res.Header.Get("Content-Type")
logger.WithCtx(c.Request.Context()).Mod("biz").Field("status", res.StatusCode).Field("content-type", ct).Info("LLMAutoSSE 上游返回成功,开始 SSE 流式转发")
// 如果上游返回的不是 SSE 流(可能是 blocking 模式返回的 JSON),直接读取并转发
if !strings.Contains(ct, "text/event-stream") && !strings.Contains(ct, "text/plain") {
body, readErr := io.ReadAll(res.Body)
if readErr != nil {View on GitHub (pinned to 3136500ef3)
Solutions
- Check the wrapped %w error to distinguish connect-refused, DNS failure, timeout, or context canceled.
- Verify the LLM endpoint/base URL configuration and test connectivity from the server: curl the endpoint.
- Confirm outbound network/DNS from the deployment environment (containers often need proxy/env settings).
- If the endpoint is right but flaky, add retry with backoff around LLMAutoStream and surface a friendly SSE error event to the client.
Example fix
// before LLM_BASE_URL=https://api.exampel.com/v1 # typo // after LLM_BASE_URL=https://api.example.com/v1 # curl -I $LLM_BASE_URL/models returns 200 first
Defensive patterns
Strategy: retry
Validate before calling
url := os.Getenv("LLM_BASE_URL")
if u, err := neturl.Parse(url); err != nil || u.Scheme == "" || u.Host == "" {
return errors.New("LLM_BASE_URL is not a valid absolute URL")
}
conn, err := net.DialTimeout("tcp", hostFromURL(url), 3*time.Second)
if err != nil { return fmt.Errorf("LLM endpoint unreachable: %w", err) }
conn.Close() Try / catch
if err := api.LLMAutoSSE(c); err != nil {
var dnsErr *net.DNSError
if errors.As(err, &dnsErr) {
c.JSON(502, gin.H{"msg": "LLM endpoint DNS failure"})
return
}
c.JSON(502, gin.H{"msg": "LLM upstream unavailable"})
} Prevention
- Validate LLM base URL and credentials at startup with a smoke request
- Ensure egress/DNS is allowed from the deployment network
- Use retry-with-backoff for dial failures
- Prefer NewRequestWithContext so cancellations are distinguishable
When it happens
Trigger: LLMAutoSSE -> streamLLMAsSSE, where LLMAutoStream fails to establish or complete the upstream HTTP request: wrong/unreachable LLM endpoint, DNS failure, TCP connect timeout, TLS handshake failure, or the request context was canceled while dialing.
Common situations: LLM base URL misconfigured (typo, http vs https), server has no outbound internet/DNS in a container, corporate firewall blocks the endpoint, provider changed its API host, or the Gin request was canceled before the upstream connected.
Related errors
- 上游大模型流式服务返回非 2xx: status=%d content-type=%s read-body-err=%w
- 上游大模型流式服务返回非 2xx: status=%d content-type=%s body=%s
- 上游大模型流式服务返回非 2xx: status=%d content-type=%s read-body-err=%w
- 读取上游流式响应失败: %w
- 调用上游大模型服务失败: %w
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/cb352405d1ef5428.
Report an issue: GitHub.