chenhg5/cc-connect · error

cloud_web: send HTTP %d: %s

Error message

cloud_web: send HTTP %d: %s

What it means

The long-poll transport POSTed an outbound message to the cloud-web send endpoint and received HTTP status >= 300, so the message was not accepted. The error carries the status code and the beginning of the response body. The transport does not retry; the caller (engine) gets this error back.

Source

Thrown at platform/cloud-web/poll.go:254

	body, err := json.Marshal(msg)
	if err != nil {
		return err
	}
	url := joinURL(t.baseURL, t.sendPath)
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	authHTTP(req, t.token)
	resp, err := t.client.Do(req)
	if err != nil {
		return err
	}
	defer func() { _ = resp.Body.Close() }()
	raw, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
	if resp.StatusCode >= 300 {
		return fmt.Errorf("cloud_web: send HTTP %d: %s", resp.StatusCode, string(raw))
	}
	// Handle inline preview_ack in send response.
	var ack wirePreviewAck
	if json.Unmarshal(raw, &ack) == nil && ack.Type == "preview_ack" && ack.RefID != "" {
		t.previewMu.Lock()
		ch, ok := t.previewRequests[ack.RefID]
		if ok {
			delete(t.previewRequests, ack.RefID)
		}
		t.previewMu.Unlock()
		if ok {
			ch <- ack.PreviewHandle
		}
	}
	return nil
}

func (t *pollTransport) waitPreviewAck(refID string, timeout time.Duration) (string, error) {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Read status from the error: 401 -> fix token; 404 -> fix base_url/send_path; 429 -> back off and reduce send rate; 5xx -> check server.
  2. Confirm the token in config.toml matches the server secret.
  3. curl the send endpoint with the same payload and Authorization header to reproduce.
  4. For transient 5xx/429, resend the message after a delay once the server recovers.

Example fix

// config.toml — before
send_path = "/v1/send"   # server serves /api/v1/send -> 404

// after
send_path = "/api/v1/send"
Defensive patterns

Strategy: retry

Validate before calling

// pre-validate send path and auth with a ping-style payload
req, _ := http.NewRequest("POST", baseURL+sendPath, strings.NewReader("{}"))
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err == nil {
    resp.Body.Close()
    if resp.StatusCode >= 300 {
        return fmt.Errorf("send endpoint returned %d before go-live", resp.StatusCode)
    }
}

Try / catch

if err := platform.Send(ctx, msg); err != nil {
    if strings.Contains(err.Error(), "send HTTP 429") {
        time.Sleep(backoff)
        return platform.Send(ctx, msg)
    }
    if strings.Contains(err.Error(), "send HTTP 5") {
        slog.Warn("server error on send; retrying once", "error", err)
        return platform.Send(ctx, msg)
    }
    return err // 401/404: configuration problem, do not retry
}

Prevention

When it happens

Trigger: Send() gets a 3xx/4xx/5xx from POST {base_url}/{send_path}: 401 token mismatch, 404 wrong base_url/send_path, 429 rate limiting, 500/502 server or proxy failure.

Common situations: Shared secret rotated without updating cc-connect; base_url pointing at a host that fronts the send API differently; server rate-limiting a chatty bot (429); upstream outage causing 502/503 through a proxy.

Related errors


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