chenhg5/cc-connect · error
create upload request: %w
Error message
create upload request: %w
What it means
http.NewRequestWithContext could not construct the POST request to the DingTalk media upload URL, almost always because the URL failed to parse. Since the URL is built with fmt.Sprintf from the access token and media type, an offending token value or malformed URL is the usual culprit.
Source
Thrown at platform/dingtalk/dingtalk.go:1365
body := bytes.NewBuffer(nil)
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("media", fileName)
if err != nil {
return "", fmt.Errorf("create form file: %w", err)
}
if _, err := part.Write(data); err != nil {
return "", fmt.Errorf("write media data: %w", err)
}
if err := writer.Close(); err != nil {
return "", fmt.Errorf("close multipart writer: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadURL, body)
if err != nil {
return "", fmt.Errorf("create upload request: %w", err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := p.httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("upload request: %w", err)
}
defer func() { _ = resp.Body.Close() }()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("read upload response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("upload returned status %d: %s", resp.StatusCode, respBody)
}View on GitHub (pinned to 4000b2338a)
Solutions
- Log/verify the access token format (it should be an opaque alphanumeric string); re-fetch the token if malformed.
- Validate mediaType is a non-empty known value ("voice" or "image") before building the URL.
- Use url.Values to encode query parameters instead of Sprintf to avoid injection/parsing issues.
- Check for control characters/whitespace in config-provided credentials and trim them.
Example fix
// before
uploadURL := fmt.Sprintf("https://oapi.dingtalk.com/media/upload?access_token=%s&type=%s", token, mediaType)
// after
q := url.Values{"access_token": {token}, "type": {mediaType}}
uploadURL := "https://oapi.dingtalk.com/media/upload?" + q.Encode() Defensive patterns
Strategy: validation
Validate before calling
if token == "" || strings.ContainsAny(token, " \t\r\n\x00") { return errors.New("malformed access token") }
if mediaType != "voice" && mediaType != "image" { return errors.New("invalid mediaType") } Prevention
- Encode query params with url.Values instead of fmt.Sprintf.
- Validate token/mediaType before constructing the URL.
- Trim whitespace from credentials at config load.
When it happens
Trigger: uploadMedia builds uploadURL := fmt.Sprintf("https://oapi.dingtalk.com/media/upload?access_token=%s&type=%s", token, mediaType) and token contains characters that break url.Parse (control characters, spaces), or mediaType is empty/invalid.
Common situations: getAccessToken returning an error-string or debug placeholder as the token; corrupted config injecting whitespace into credentials; a refactor changing mediaType to an empty value.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- dingtalk: create emotion request: %w
- dingtalk: upload image: %w
- upload request: %w
- read upload response: %w
- upload returned status %d: %s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/f246f83d485ee75a.
Report an issue: GitHub.