chenhg5/cc-connect · error
request upload url: %w
Error message
request upload url: %w
What it means
This wraps a transport-level failure of the first step of the MAX two-step upload: the GET/POST to /uploads?type=<kind> that requests a temporary upload URL. The library did not even get an HTTP response — the request failed at the network layer (DNS, TLS, timeout, connection reset).
Source
Thrown at platform/max/max.go:553
}
// 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
// and would abort large CDN uploads before the context expires.
uploadCtx, cancel := context.WithTimeout(ctx, attachmentUploadTO)
defer cancel()
urlReq, err := http.NewRequestWithContext(uploadCtx, http.MethodPost, p.apiBase+"/uploads", nil)
if err != nil {
return "", err
}
p.setAuth(urlReq)
q := urlReq.URL.Query()
q.Set("type", kind)
urlReq.URL.RawQuery = q.Encode()
urlResp, err := p.uploadClient.Do(urlReq)
if err != nil {
return "", fmt.Errorf("request upload url: %w", err)
}
defer urlResp.Body.Close()
if urlResp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(urlResp.Body, 512))
return "", fmt.Errorf("upload url: HTTP %d: %s", urlResp.StatusCode, body)
}
var urlInfo struct {
URL string `json:"url"`
Token string `json:"token"`
}
if err := json.NewDecoder(urlResp.Body).Decode(&urlInfo); err != nil {
return "", fmt.Errorf("decode upload url: %w", err)
}
if urlInfo.URL == "" {
return "", fmt.Errorf("upload url: empty url in response")
}
if filename == "" {View on GitHub (pinned to 4000b2338a)
Solutions
- Check outbound network connectivity and DNS for the MAX API host from the deployment environment
- Inspect the wrapped error (%w) for context.DeadlineExceeded vs connection errors to decide retry vs abort
- Verify proxy/firewall settings allow HTTPS to the MAX API
- Retry transient network errors with backoff; propagate cancellation for user-initiated aborts
Example fix
// before
token, err := p.uploadAttachment(ctx, "file", data, name)
if err != nil { return err }
// after
token, err := p.uploadAttachment(ctx, "file", data, name)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return fmt.Errorf("max: upload timed out for %s (%d bytes)", name, len(data))
}
return err
} Defensive patterns
Strategy: retry
Validate before calling
if err := ctx.Err(); err != nil { return err } // ensure context still alive before starting upload Try / catch
var nerr net.Error
if errors.As(err, &nerr) && nerr.Timeout() {
// retry with backoff, larger timeout
}
if errors.Is(err, context.Canceled) {
return err // user aborted, do not retry
} Prevention
- Use a context with adequate deadline for large uploads (the lib uses 5 minutes)
- Confirm egress/proxy allows HTTPS to the MAX API host from production
- Distinguish cancellation (do not retry) from timeouts (retry) via errors.Is/As
- Set sensible http.Client timeouts on custom clients
When it happens
Trigger: SendImage/SendFile/SendAudio calling uploadAttachment when p.uploadClient.Do(urlReq) errors: no network, DNS failure, TLS error, context deadline exceeded (5-minute attachmentUploadTO or parent ctx cancelled), or upload client misconfigured proxy.
Common situations: Uploading large files from a container with no outbound internet; corporate proxy blocking bot-api host; user cancels the operation and the parent context is cancelled mid-upload; slow CDN causing the 5-minute timeout.
Related errors
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/4f18c04719b498c9.
Report an issue: GitHub.