flipped-aurora/gin-vue-admin · error

构建请求失败: %w

Error message

构建请求失败: %w

What it means

fetchPublicUpstream is a generic helper that GETs a public upstream endpoint with a timeout. This error wraps http.NewRequestWithContext failures — the HTTP request object could not be constructed, almost always because the final URL (upstreamURL(path)) is malformed (bad scheme, control characters, unparseable host).

Source

Thrown at server/mcp/http_client.go:114

	timeout := global.GVA_CONFIG.MCP.RequestTimeout
	if timeout <= 0 {
		timeout = 15
	}
	return time.Duration(timeout) * time.Second
}

// 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]

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Inspect upstreamURL(path) — log the final URL and verify it parses (url.Parse succeeds) and has an absolute http/https scheme
  2. Fix the upstream base URL in the server config (no stray spaces, correct scheme/host)
  3. Sanitize/encode the path segment before calling fetchPublicUpstream

Example fix

// before
upstreamBase := cfg.UpstreamBase // "localhost:9999" (no scheme)
// after
upstreamBase := "http://localhost:9999" // absolute URL with scheme
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(upstreamURL(path))
if err != nil || u.Scheme == "" || u.Host == "" {
  return fmt.Errorf("invalid upstream URL %q", u)
}

Type guard

func isValidUpstreamURL(raw string) bool {
  u, err := url.Parse(raw)
  return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
}

Try / catch

req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
  return nil, fmt.Errorf("build request failed: %w", err)
}

Prevention

When it happens

Trigger: Calling any MCP tool that hits the public upstream while the configured upstream base URL is empty or invalid, or path concatenation yields an unparseable URL (spaces, newline, missing scheme).

Common situations: Missing/typo'd upstream base in config producing 'http://:8080/...' or relative URL; config value carrying whitespace or BOM; path containing unescaped characters.

Related errors


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