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 list

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Confirm the reasonix serve process is running and listening (curl the serveURL health endpoint)
  2. Check the wrapped error: 'connection refused' means wrong port/dead process; 'context canceled' means the session was closed mid-request
  3. Correct serve_url in config.toml (host/port) and restart
  4. 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

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


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