chenhg5/cc-connect · error
upload url: HTTP %d: %s
Error message
upload url: HTTP %d: %s
What it means
Returned when the MAX /uploads endpoint responds with a non-200 status during the first step of the two-step upload. The library includes the HTTP status code and up to 512 bytes of the response body so the exact server-side rejection is visible. The upload never started — no upload URL was obtained.
Source
Thrown at platform/max/max.go:558
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 == "" {
filename = defaultFilename(kind)
}
var buf bytes.Buffer
mw := multipart.NewWriter(&buf)
fw, err := mw.CreateFormFile("data", filename)View on GitHub (pinned to 4000b2338a)
Solutions
- Read the status/body in the error message to get the exact rejection reason
- Verify the bot token used to build urlReq is valid and not expired
- Check the kind parameter matches what the API accepts for the attachment type
- If 413, reduce file size before uploading; if 429/5xx, retry with backoff
Example fix
// before
return "", fmt.Errorf("upload url: HTTP %d: %s", urlResp.StatusCode, body)
// after (caller-side handling)
if err != nil && strings.Contains(err.Error(), "HTTP 401") {
return fmt.Errorf("max: upload auth failed, check bot token: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if botToken == "" { return errors.New("bot token missing; cannot upload attachment") } Try / catch
if err != nil {
switch {
case strings.Contains(err.Error(), "HTTP 401"), strings.Contains(err.Error(), "HTTP 403"):
return fmt.Errorf("check bot token: %w", err)
case strings.Contains(err.Error(), "HTTP 429"), strings.Contains(err.Error(), "HTTP 5"):
// retry with backoff
default:
return err
}
} Prevention
- Validate the bot token at startup (TestConnection/doctor flow)
- Keep declared Content-Type/kind consistent with the actual attachment
- Handle 429 with exponential backoff to respect rate limits
- Monitor the body text in the error for API quota/auth messages
When it happens
Trigger: uploadAttachment (via SendImage/SendFile/SendAudio) receiving 401/403 (invalid bot token), 400 (unsupported type=<kind> value), 413 (declared file too large), or 5xx from the /uploads endpoint.
Common situations: Expired or wrong bot token; sending an attachment kind the API does not accept (e.g. wrong type parameter); MAX API outage; upload quota exhausted on the bot.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- upload url: empty url in response
- cdn upload: HTTP %d: %s
- upload returned status %d: %s
- max: edit message: HTTP %d: %s
- cdn upload: no token in response: %s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/a5f565f5d21927a9.
Report an issue: GitHub.