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
- Read status from the error: 401 -> fix token; 404 -> fix base_url/send_path; 429 -> back off and reduce send rate; 5xx -> check server.
- Confirm the token in config.toml matches the server secret.
- curl the send endpoint with the same payload and Authorization header to reproduce.
- 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
- Classify failures: retry 429/5xx with backoff; fix config for 401/404
- Reduce send rate or batch messages if the server rate-limits (429)
- Verify base_url and send_path after every server route change
- Include the send endpoint in deployment smoke tests
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
- cloud_web: send HTTP %d: %s
- qwen asr API %d: %s
- gemini stt API %d: %s
- cloud_web: register HTTP %d: %s
- cloud_web: register HTTP %d: %s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/306eab2da961a57e.
Report an issue: GitHub.