chenhg5/cc-connect · error

dingtalk: send image request: %w

Error message

dingtalk: send image request: %w

What it means

Returned by SendImage when the actual HTTP POST to DingTalk's oToMessages batchSend API fails at the transport level (connection error, timeout, TLS failure). It wraps the underlying net/http error, so the root cause is in the wrapped message.

Source

Thrown at platform/dingtalk/dingtalk.go:1061

	}

	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)
	return nil
}

var _ core.ImageSender = (*Platform)(nil)
var _ core.StreamingCardPlatform = (*Platform)(nil)
var _ core.ReplyContextReconstructor = (*Platform)(nil)
var _ core.TypingIndicator = (*Platform)(nil)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Inspect the wrapped error for the transport cause (dial timeout, TLS, DNS)
  2. Verify egress connectivity: curl https://api.dingtalk.com from the host
  3. Increase p.httpClient timeout if requests are large or the network is slow
  4. Retry with backoff on transient errors (net.Error, timeouts); check DingTalk status page during outages

Example fix

// before
cfg.HTTPClient.Timeout = 2 * time.Second
// after
cfg.HTTPClient.Timeout = 15 * time.Second // allow for slow DingTalk API responses
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.DialTimeout("tcp", "api.dingtalk.com:443", 5*time.Second)
if err != nil {
    return fmt.Errorf("no egress to api.dingtalk.com: %w", err)
}
conn.Close()

Try / catch

var ne net.Error
if err := p.SendImage(ctx, rc, img); err != nil {
    if errors.As(err, &ne) && ne.Timeout() {
        // transient: retry with backoff
    }
    return err
}

Prevention

When it happens

Trigger: Network outage or DNS failure reaching api.dingtalk.com; request timeout from p.httpClient; TLS interception/proxy issues; context cancelled mid-request.

Common situations: Corporate proxy blocking api.dingtalk.com; HTTP client timeout too small for large deployments; container losing egress; DingTalk API regional outage.

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/75e3aa7dc5311c08. Report an issue: GitHub.