chenhg5/cc-connect · error

qqbot: build retry request: %w

Error message

qqbot: build retry request: %w

What it means

After a 401 and successful token refresh, apiRequestJSON rebuilds the request with http.NewRequest before retrying. If constructing that retry request fails, this error is raised. This is rare — http.NewRequest only fails on a malformed URL or an invalid method — and points at an internal URL-construction problem rather than the API itself.

Source

Thrown at platform/qqbot/qqbot.go:345

	if err != nil {
		return fmt.Errorf("qqbot: api request failed: %w", err)
	}
	defer resp.Body.Close()

	// Retry once on 401
	if resp.StatusCode == http.StatusUnauthorized {
		if err := p.refreshToken(); err != nil {
			return fmt.Errorf("qqbot: token refresh on 401: %w", err)
		}
		token, _ = p.getAccessToken()

		if body != nil {
			data, _ := json.Marshal(body)
			bodyReader = bytes.NewReader(data)
		}
		req2, err := http.NewRequest(method, url, bodyReader)
		if err != nil {
			return fmt.Errorf("qqbot: build retry request: %w", err)
		}
		req2.Header.Set("Authorization", "QQBot "+token)
		req2.Header.Set("Content-Type", "application/json")

		resp2, err := core.HTTPClient.Do(req2)
		if err != nil {
			return fmt.Errorf("qqbot: api retry failed: %w", err)
		}
		defer resp2.Body.Close()

		if resp2.StatusCode >= 300 {
			raw, _ := io.ReadAll(resp2.Body)
			return fmt.Errorf("qqbot: api %s %s returned %d (after retry): %s", method, url, resp2.StatusCode, raw)
		}
		if result != nil {
			if err := json.NewDecoder(resp2.Body).Decode(result); err != nil {
				return fmt.Errorf("qqbot: decode response: %w", err)
			}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Inspect the wrapped error — it names the URL parse failure.
  2. Verify the groupOpenID/userOpenID in the reply context is a valid non-empty ID.
  3. Check p.apiBase()/config for a malformed api_base value (missing scheme, stray spaces).
  4. If IDs come from an inbound event, re-check that the event was parsed correctly before replying.

Example fix

// before (config.toml)
api_base = "qqbot-api.example"
// after
api_base = "https://api.sgroup.qq.com"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(apiBase)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid qqbot api_base: %q", apiBase)
}

Try / catch

if err := send(); err != nil {
    if strings.Contains(err.Error(), "build retry request") {
        slog.Error("qqbot URL construction bug", "err", err)
    }
}

Prevention

When it happens

Trigger: HTTP 401 received, token refresh succeeded, but http.NewRequest(method, url, ...) fails while building the retry request — a malformed endpoint URL or invalid HTTP method passed into apiRequestJSON.

Common situations: Practically only seen if p.apiBase() or a message/groupOpenID interpolated into the URL is empty or contains characters that break URL parsing; effectively an internal invariant issue.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/20efa85f28ed27f1. Report an issue: GitHub.