chenhg5/cc-connect · error

gateway response decode: %w

Error message

gateway response decode: %w

What it means

Returned when the HTTP response body from the QQ gateway endpoint cannot be decoded as JSON into the struct {url string}. Usually the body is HTML (error page), empty, or truncated instead of the expected JSON.

Source

Thrown at platform/qqbot/qqbot.go:702

func (p *Platform) getGatewayURL(token string) (string, error) {
	req, err := http.NewRequest("GET", p.apiBase()+"/gateway/bot", nil)
	if err != nil {
		return "", err
	}
	req.Header.Set("Authorization", "QQBot "+token)

	resp, err := core.HTTPClient.Do(req)
	if err != nil {
		return "", fmt.Errorf("gateway request failed: %w", err)
	}
	defer resp.Body.Close()

	var result struct {
		URL string `json:"url"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return "", fmt.Errorf("gateway response decode: %w", err)
	}
	if result.URL == "" {
		return "", fmt.Errorf("empty gateway URL in response")
	}
	return result.URL, nil
}

type wsPayload struct {
	Op int             `json:"op"`
	D  json.RawMessage `json:"d,omitempty"`
	S  *int64          `json:"s,omitempty"`
	T  string          `json:"t,omitempty"`
}

func (p *Platform) waitForHello(conn *websocket.Conn) error {
	_ = conn.SetReadDeadline(time.Now().Add(15 * time.Second))
	defer func() { _ = conn.SetReadDeadline(time.Time{}) }()

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Log the HTTP status code and raw body on decode failure to see what was actually returned
  2. Check for proxy/WAF interference between the host and QQ
  3. Verify the access token is valid — invalid auth often yields non-JSON error bodies
  4. Retry; if persistent, capture the response body for a bug report

Example fix

// before
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
    return "", fmt.Errorf("gateway response decode: %w", err)
}
// after
raw, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
    return "", fmt.Errorf("gateway http %d: %s", resp.StatusCode, raw)
}
if err := json.Unmarshal(raw, &result); err != nil {
    return "", fmt.Errorf("gateway response decode: %w (body: %.200s)", err, raw)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if resp.StatusCode != http.StatusOK {
    return fmt.Errorf("gateway returned %d", resp.StatusCode)
}

Try / catch

body, readErr := io.ReadAll(resp.Body)
if err := json.Unmarshal(body, &result); err != nil {
    slog.Error("gateway non-JSON response", "status", resp.StatusCode, "body", string(body), "err", readErr)
    return retryOrFallback()
}

Prevention

When it happens

Trigger: json.NewDecoder(resp.Body).Decode fails because the gateway endpoint returned a non-JSON body — e.g. an HTML error page from a proxy, an empty body from a 5xx, or a WAF interception page.

Common situations: QQ returns an HTML rate-limit or WAF block page; a corporate proxy injects an auth page; server returns gzip/encoding the decoder can't handle transparently.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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