flipped-aurora/gin-vue-admin · error

请求上游接口失败: %w

Error message

请求上游接口失败: %w

What it means

The same helper fails with this error when http.DefaultClient.Do returns an error: DNS resolution failure, connection refused/reset, TLS errors, or the context deadline (defaultUpstreamTimeout) expiring before the response arrives.

Source

Thrown at server/mcp/http_client.go:120

// defaultUpstreamTimeout 是回打主服务公共(免鉴权)接口的默认超时。
const defaultUpstreamTimeout = 10 * time.Second

// fetchPublicUpstream 回打主服务的公共(免鉴权)接口:带超时的 GET + 标准信封解析。
// 动态 tool 与编排 prompt 的注册共用同一模式,T 为信封 Data 字段的具体负载类型。
func fetchPublicUpstream[T any](path string) (*upstreamEnvelope[T], error) {
	timeoutCtx, cancel := context.WithTimeout(context.Background(), defaultUpstreamTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(timeoutCtx, http.MethodGet, upstreamURL(path), nil)
	if err != nil {
		return nil, fmt.Errorf("构建请求失败: %w", err)
	}
	req.Header.Set("Accept", "application/json")

	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)
	}
	if resp.StatusCode >= http.StatusBadRequest {
		return nil, fmt.Errorf("上游接口返回状态码 %d: %s", resp.StatusCode, string(rawBody))
	}

	var result upstreamEnvelope[T]
	if err := json.Unmarshal(rawBody, &result); err != nil {
		return nil, fmt.Errorf("解析响应失败: %w", err)
	}
	if result.Code != 0 {
		return nil, fmt.Errorf("上游接口业务错误: %s", result.Msg)
	}

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Check the wrapped error message for root cause (dial tcp: connection refused / no such host / context deadline exceeded)
  2. Verify the upstream service is reachable: curl the same URL from the server host
  3. If timeouts are the cause, review defaultUpstreamTimeout and upstream load
  4. Check DNS/egress rules (proxy env, firewall) in the deployment environment

Example fix

// before
resp, err := http.DefaultClient.Do(req) // context deadline exceeded
// after
client := &http.Client{Timeout: 30 * time.Second} // and ensure upstream is reachable
resp, err := client.Do(req)
Defensive patterns

Strategy: retry

Validate before calling

// pre-check reachability before invoking the tool
conn, err := net.DialTimeout("tcp", host, 3*time.Second)
if err != nil { return fmt.Errorf("upstream unreachable: %w", err) }
conn.Close()

Type guard

func isTimeoutErr(err error) bool { return errors.Is(err, context.DeadlineExceeded) || errors.Is(err, os.ErrDeadlineExceeded) }

Try / catch

resp, err := client.Do(req)
if err != nil {
  if isTimeoutErr(err) {
    return nil, fmt.Errorf("upstream timeout, retry later: %w", err)
  }
  return nil, fmt.Errorf("upstream request failed: %w", err)
}
defer resp.Body.Close()

Prevention

When it happens

Trigger: GET to the public upstream endpoint fails at transport level: upstream down, wrong host/port, firewall, DNS outage, or slow upstream exceeding defaultUpstreamTimeout.

Common situations: Upstream service not running during local dev; network egress blocked in CI/container; typo in upstream hostname; upstream latency spike triggering the timeout; TLS cert expired on the upstream.

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/0daa4e89234165fe. Report an issue: GitHub.