chenhg5/cc-connect · error
max: edit message: %w
Error message
max: edit message: %w
What it means
This wraps a transport-level failure of the PUT /messages?message_id= request used to edit a MAX message: p.client.Do returned an error before an HTTP response could be read. The wrapped cause is typically a timeout (p.client has a 35s timeout), connection refused/reset, DNS failure, or request-context cancellation — i.e. the edit request never completed, so the message text is unchanged.
Source
Thrown at platform/max/max.go:519
}
body := maxSendBody{Text: content, Format: "markdown"}
data, err := json.Marshal(body)
if err != nil {
return err
}
req, err := http.NewRequestWithContext(ctx, http.MethodPut, p.apiBase+"/messages", bytes.NewReader(data))
if err != nil {
return err
}
p.setAuth(req)
q := req.URL.Query()
q.Set("message_id", rctx.messageID)
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: edit message: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
return fmt.Errorf("max: edit message: HTTP %d: %s", resp.StatusCode, respBody)
}
return nil
}
// uploadAttachment performs the two-step MAX upload: request an upload URL from
// /uploads?type=<kind>, then POST the binary as multipart/form-data field "data"
// to that URL. Returns the token to embed in a subsequent /messages attachment.
func (p *Platform) uploadAttachment(ctx context.Context, kind string, data []byte, filename string) (string, error) {
if len(data) == 0 {
return "", fmt.Errorf("empty attachment data")
}
// Use a 5-minute context AND a dedicated http.Client with a matching Timeout.
// p.client has a 35 s Timeout which fires independently of the context deadlineView on GitHub (pinned to 4000b2338a)
Solutions
- Check connectivity from the host to the MAX API endpoint (curl the API base) to distinguish network outage from code issues.
- Implement retry with backoff for transient transport errors (errors.Is(err, context.DeadlineExceeded), net.Error Timeout(), connection reset) — edits are idempotent per message_id.
- Verify the outbound context passed to UpdateMessage isn't canceled too early (e.g. a short request timeout upstream).
- Check proxy/firewall settings (HTTPS_PROXY, TLS interception) on the machine running cc-connect.
- Throttle rapid successive edits of the same message to avoid hammering the connection.
Example fix
// before
err := platform.UpdateMessage(ctx, rctx, newText)
if err != nil { return err }
// after
err := platform.UpdateMessage(ctx, rctx, newText)
if err != nil {
var ne net.Error
if errors.As(err, &ne) && ne.Timeout() || errors.Is(err, context.DeadlineExceeded) {
time.Sleep(500 * time.Millisecond)
return platform.UpdateMessage(ctx, rctx, newText) // retry transient failure
}
return fmt.Errorf("max: edit message: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
select {
case <-ctx.Done():
return ctx.Err() // don't even attempt if already canceled
default:
} Try / catch
err := platform.UpdateMessage(ctx, replyCtx, content)
if err != nil {
var ne net.Error
if errors.As(err, &ne) && ne.Timeout() ||
errors.Is(err, syscall.ECONNRESET) || errors.Is(err, syscall.ECONNREFUSED) {
time.Sleep(backoff) // then retry once or twice
return platform.UpdateMessage(ctx, replyCtx, content)
}
return err
} Prevention
- Add bounded retry with exponential backoff for transport errors — edits are idempotent for a given message_id.
- Keep the 35s client timeout in mind; pass a caller context with a slightly larger deadline so cancellation is deliberate, not accidental.
- Monitor outbound connectivity/proxy health to the MAX API host; alert on repeated edit failures.
- Rate-limit successive edits of the same message to reduce connection churn.
- Treat this as transient when message text correctness matters: re-read state and re-apply the edit after recovery.
When it happens
Trigger: Calling UpdateMessage when: (1) the 35s http.Client timeout fires on a slow/hung connection; (2) the caller's context is canceled mid-request; (3) TCP connection to botapi.max.ru fails (connection refused, reset, TLS handshake failure); (4) DNS resolution fails; (5) a proxy intercepts and breaks the connection.
Common situations: Streaming-style frequent edits causing many rapid PUTs over a flaky mobile link; daemon running behind a corporate proxy that drops keep-alive connections; host with intermittent DNS; the caller cancels the context (user sent a new command) while the edit is in flight.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- openai tts: request: %w
- max: upload audio: %w
- max: update message: no message id in reply context
- listen for Agy permission hooks: %w
- antigravity permission bridge: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/9845120a8238aae6.
Report an issue: GitHub.