chenhg5/cc-connect · error

max: send message: %w

Error message

max: send message: %w

What it means

The HTTP request that delivers the outbound message to the MAX send-message endpoint failed at the transport level; the underlying error is wrapped with %w. This happens before any status code is available.

Source

Thrown at platform/max/max.go:1397

	data, err := json.Marshal(body)
	if err != nil {
		return err
	}
	backoff := attachmentReadyDelay
	for attempt := 0; attempt <= attachmentReadyRetries; attempt++ {
		req, err := http.NewRequestWithContext(ctx, http.MethodPost, p.apiBase+"/messages", bytes.NewReader(data))
		if err != nil {
			return err
		}
		p.setAuth(req)
		q := req.URL.Query()
		q.Set("chat_id", chatID)
		req.URL.RawQuery = q.Encode()
		req.Header.Set("Content-Type", "application/json")

		resp, err := p.client.Do(req)
		if err != nil {
			return fmt.Errorf("max: send message: %w", err)
		}
		respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 2048))
		resp.Body.Close()

		if resp.StatusCode == http.StatusOK {
			return nil
		}
		if isAttachmentNotReady(respBody) && attempt < attachmentReadyRetries {
			slog.Debug("max: attachment not ready, retrying", "attempt", attempt+1, "backoff", backoff)
			select {
			case <-ctx.Done():
				return ctx.Err()
			case <-time.After(backoff):
			}
			backoff *= 2
			continue
		}
		slog.Warn("max: send message failed", "status", resp.StatusCode, "chat", chatID, "body", string(respBody))

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Inspect the wrapped cause with errors.Unwrap / %v to see if it is DNS, connect, or timeout
  2. Verify network connectivity and DNS for apiBase from the bot host
  3. Check proxy env vars (HTTPS_PROXY) if behind a corporate proxy
  4. Increase the send timeout or add retry with backoff for transient transport errors

Example fix

// before
if err := p.client.Do(req); err != nil {
	return fmt.Errorf("max: send message: %w", err)
}
// after
if err := p.client.Do(req); err != nil {
	if ctx.Err() != nil {
		return fmt.Errorf("max: send message: canceled: %w", ctx.Err())
	}
	return fmt.Errorf("max: send message: %w", err) // caller retries on net.Error
}
Defensive patterns

Strategy: retry

Validate before calling

if _, err := net.LookupHost(host(apiBase)); err != nil { failFast("MAX apiBase unresolvable") }

Try / catch

err := p.Send(ctx, chat, text)
var nerr net.Error
if errors.As(err, &nerr) && nerr.Timeout() {
	ctx2, c := context.WithTimeout(context.Background(), 15*time.Second)
	defer c(); retryWith(ctx2)
}

Prevention

When it happens

Trigger: DNS failure, connection refused/reset, TLS errors, or context timeout/deadline exceeded while POSTing to p.apiBase-based send endpoint.

Common situations: No internet access or DNS misconfiguration on the host; MAX API outage; proxy/firewall blocking outbound HTTPS; overly aggressive timeout cancelling in-flight requests.

Related errors


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