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 deadline

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check connectivity from the host to the MAX API endpoint (curl the API base) to distinguish network outage from code issues.
  2. Implement retry with backoff for transient transport errors (errors.Is(err, context.DeadlineExceeded), net.Error Timeout(), connection reset) — edits are idempotent per message_id.
  3. Verify the outbound context passed to UpdateMessage isn't canceled too early (e.g. a short request timeout upstream).
  4. Check proxy/firewall settings (HTTPS_PROXY, TLS interception) on the machine running cc-connect.
  5. 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

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


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