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

  1. Log/verify the access token format (it should be an opaque alphanumeric string); re-fetch the token if malformed.
  2. Validate mediaType is a non-empty known value ("voice" or "image") before building the URL.
  3. Use url.Values to encode query parameters instead of Sprintf to avoid injection/parsing issues.
  4. 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

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


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