flipped-aurora/gin-vue-admin · error
请求上游服务失败: %w
Error message
请求上游服务失败: %w
What it means
http.DefaultClient.Do returned a transport-level error (connection refused, DNS failure, TLS error, timeout via the request context); it is wrapped as '请求上游服务失败'. The request never received an HTTP response, so the problem is network/connectivity, not the upstream's answer.
Source
Thrown at server/mcp/http_client.go:203
timeoutCtx, cancel := context.WithTimeout(ctx, requestTimeout())
defer cancel()
req, err := http.NewRequestWithContext(timeoutCtx, method, requestURL.String(), reader)
if err != nil {
return nil, fmt.Errorf("创建上游请求失败: %w", err)
}
req.Header.Set("Accept", "application/json")
req.Header.Set(upstreamAuthHeader, token)
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
// 链路传播:外部 AI → MCP 进程 → GVA 主服务串成同一条 trace
logger.InjectTraceHeaders(timeoutCtx, req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("请求上游服务失败: %w", err)
}
defer resp.Body.Close()
rawBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取上游响应失败: %w", err)
}
var result upstreamEnvelope[T]
if len(rawBody) > 0 {
if err := json.Unmarshal(rawBody, &result); err != nil {
// 上游返回非 JSON(如 404/502 的 HTML 或网关错误页):先暴露真实状态码,
// 不让解析错误掩盖真实的 HTTP 失败
if resp.StatusCode >= http.StatusBadRequest {
return nil, fmt.Errorf("上游请求失败,状态码: %d,响应: %s", resp.StatusCode, truncateUpstreamBody(rawBody))
}
return nil, fmt.Errorf("解析上游响应失败: %w", err)
}View on GitHub (pinned to 3136500ef3)
Solutions
- Check the wrapped error: 'connection refused' → upstream down/wrong port; 'no such host' → DNS; 'context deadline exceeded' → timeout
- Confirm the GVA server is running and listening at the host:port in upstreamBaseURL
- curl the same base URL from the MCP process's network position to reproduce
- If it is a timeout, raise requestTimeout() or optimize the slow upstream endpoint
- In containers, fix the base URL to the service hostname instead of localhost
Defensive patterns
Strategy: retry
Validate before calling
func upstreamAlive(ctx context.Context, base string) error {
c, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(c, http.MethodGet, strings.TrimRight(base, "/")+"/health", nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
resp.Body.Close()
return nil
} Try / catch
result, err := getUpstream[Data](ctx, "/api/x", nil)
if err != nil {
if strings.Contains(err.Error(), "请求上游服务失败") {
// classify: refused → down, no such host → DNS, deadline exceeded → timeout
// apply bounded retry with backoff for transient cases
}
return err
} Prevention
- Confirm the GVA server is running before starting the MCP process
- Use the correct container-internal hostname, not localhost, when sandboxed
- Set requestTimeout() generously for known-slow endpoints
- Add health-check startup gating so tools fail fast with a clear message
- Monitor DNS/TLS changes in the deployment environment
When it happens
Trigger: GVA main service not running or listening on a different port than upstreamBaseURL; firewall/security group blocking; DNS name unresolvable; requestTimeout() elapsed before a response; TLS certificate problems on https base URLs.
Common situations: Dev environment where the backend port changed; upstreamBaseURL pointing to localhost from inside a container (should use host.docker.internal/service name); server overloaded and exceeding the timeout; VPN/proxy required for the upstream address.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/d8d749baba3d25ab.
Report an issue: GitHub.