chenhg5/cc-connect · error

dingtalk: create image request: %w

Error message

dingtalk: create image request: %w

What it means

Returned by SendImage when http.NewRequestWithContext fails to construct the POST to DingTalk's robot/oToMessages/batchSend endpoint. This only happens if the HTTP method or URL string is invalid, or ctx is already cancelled, so it indicates a programming bug or an expired context rather than a runtime network issue.

Source

Thrown at platform/dingtalk/dingtalk.go:1054

	msgParamBytes, _ := json.Marshal(map[string]string{"photoURL": mediaID})
	requestBody := map[string]any{
		"robotCode": p.robotCode,
		"userIds":   []string{rc.senderStaffId},
		"msgKey":    "sampleImageMsg",
		"msgParam":  string(msgParamBytes),
	}

	body, err := json.Marshal(requestBody)
	if err != nil {
		return fmt.Errorf("dingtalk: marshal image message: %w", err)
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodPost,
		"https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend",
		bytes.NewReader(body))
	if err != nil {
		return fmt.Errorf("dingtalk: create image request: %w", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("x-acs-dingtalk-access-token", token)

	resp, err := p.httpClient.Do(req)
	if err != nil {
		return fmt.Errorf("dingtalk: send image request: %w", err)
	}
	defer func() { _ = resp.Body.Close() }()

	respBody, _ := io.ReadAll(resp.Body)
	slog.Debug("dingtalk: oToMessages image response", "status", resp.StatusCode, "body", string(respBody))

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("dingtalk: send image failed: status=%d, body=%s", resp.StatusCode, string(respBody))
	}

	slog.Info("dingtalk: image message sent", "media_id", mediaID, "user", rc.senderStaffId)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check that the context passed to SendImage is alive at call time; do not reuse a cancelled context
  2. Wrap the call and inspect errors.Is(err, context.Canceled) / context.DeadlineExceeded to distinguish cancellation from a bug
  3. Verify the platform code version — the URL is hard-coded, so a malformed URL would mean a corrupted build
  4. If cancellation is expected during shutdown, tolerate this error and retry after re-init

Example fix

// before
if err := p.SendImage(ctx, rc, img); err != nil { log.Fatal(err) }
// after
if err := p.SendImage(ctx, rc, img); err != nil {
    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
        return // shutdown path
    }
    log.Fatal(err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if ctx.Err() != nil {
    return fmt.Errorf("context already done, skip SendImage: %w", ctx.Err())
}

Try / catch

if err := p.SendImage(ctx, rc, img); err != nil {
    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
        return nil // expected during shutdown
    }
    return fmt.Errorf("dingtalk image send failed: %w", err)
}

Prevention

When it happens

Trigger: Calling SendImage while the passed context is already cancelled/deadline-exceeded, or (theoretically) if the hard-coded endpoint URL is malformed.

Common situations: Caller passes a context whose deadline lapsed before the send; shutdown race where engine cancels ctx then still calls SendImage.

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/81cd36e8e4459158. Report an issue: GitHub.