chenhg5/cc-connect · error
reasonix: POST %s: %w
Error message
reasonix: POST %s: %w
What it means
httpPost performs the request with http.DefaultClient.Do and wraps any transport-level failure as 'reasonix: POST %s: %w'. This covers DNS failure, connection refused, TLS errors, timeouts, and — importantly — context cancellation of the session (e.g. session closed while a request was in flight).
Source
Thrown at agent/reasonix/session.go:492
func (s *reasonixSession) httpPost(path string, body any) error {
var reqBody io.Reader
if body != nil {
data, err := json.Marshal(body)
if err != nil {
return fmt.Errorf("reasonix: marshal body: %w", err)
}
reqBody = bytes.NewReader(data)
}
req, err := http.NewRequestWithContext(s.ctx, "POST", s.serveURL+path, reqBody)
if err != nil {
return fmt.Errorf("reasonix: create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("reasonix: POST %s: %w", path, err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
slog.Warn("reasonix: POST close body", "path", path, "error", err)
}
}()
if resp.StatusCode >= 400 {
// Include response body (first 512 bytes) in error for debugging.
errBody, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
return fmt.Errorf("reasonix: POST %s returned %d: %s", path, resp.StatusCode, strings.TrimSpace(string(errBody)))
}
return nil
}
// formatImages builds a comma-separated list of image filenames for inclusion
// in the prompt. Reasons adopts the standard cc-connect file-save pattern so
// the actual image bytes land on disk (via core.SaveFilesToDisk); this listView on GitHub (pinned to 4000b2338a)
Solutions
- Confirm the reasonix serve process is running and listening (curl the serveURL health endpoint)
- Check the wrapped error: 'connection refused' means wrong port/dead process; 'context canceled' means the session was closed mid-request
- Correct serve_url in config.toml (host/port) and restart
- If context-canceled races are frequent, guard Send/RespondPermission with an alive check before issuing requests
Example fix
// before: request races session shutdown
err := s.httpPost("/message", body)
// after: bail early on closed session
if s.ctx.Err() != nil {
return fmt.Errorf("reasonix: session closed")
}
err := s.httpPost("/message", body) Defensive patterns
Strategy: retry
Validate before calling
// probe before use
resp, err := http.Get(serveURL + "/health")
if err != nil { return fmt.Errorf("reasonix serve unreachable: %w", err) } Try / catch
// Go: distinguish cancel vs transport failure
if err := sess.Send(...); err != nil {
if errors.Is(err, context.Canceled) {
return // session closed; don't retry
}
// transient network failure: retry with backoff
retry.WithBackoff(3, func() error { return sess.Send(...) })
} Prevention
- Start the reasonix serve process before cc-connect and supervise it (systemd)
- Health-check the endpoint at startup and on a timer
- Match host/port between serve and config; avoid timeout-prone proxies on localhost
When it happens
Trigger: During newSession, Send, or RespondPermission the POST to the reasonix serve endpoint fails at the transport layer: serve process not running, wrong host/port, network partition, TLS handshake failure, or s.ctx already canceled.
Common situations: Reasonix serve not started before cc-connect; serve_url pointing at the wrong port; firewall blocking localhost; long Send hitting an idle timeout; session Stop() racing an in-flight RespondPermission.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- wecom: send message: %w
- range chunk retries exhausted
- connect permission bridge: %w
- request usage endpoint: %w
- init failed: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/6d31d4e2f3d6e5fe.
Report an issue: GitHub.