chenhg5/cc-connect · error

dingtalk: send audio request: %w

Error message

dingtalk: send audio request: %w

What it means

This error wraps a failure from httpClient.Do when executing the audio voice-message request to DingTalk's oToMessages batchSend endpoint. The request was built but the HTTP round trip failed: DNS, connect, TLS, timeout, or context cancellation. No response was received from DingTalk.

Source

Thrown at platform/dingtalk/dingtalk.go:1281

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

	slog.Debug("dingtalk: sending voice via oToMessages API", "media_id", mediaID, "duration", durationMs, "user_id", rc.senderStaffId)

	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 audio 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 audio request: %w", err)
	}
	defer func() { _ = resp.Body.Close() }()

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

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

	slog.Info("dingtalk: voice message sent successfully", "media_id", mediaID, "conversation_id", rc.conversationId)
	return nil
}

// compressAudio compresses audio if it exceeds size limits.
// Uses ffmpeg to convert WAV to MP3 format (DingTalk supported, ~10:1 compression ratio).
func (p *Platform) compressAudio(ctx context.Context, audio []byte, format string) ([]byte, string, error) {
	// Only WAV format can be compressed to MP3

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check the wrapped error: timeout vs connection refused vs context cancelled
  2. Test connectivity: curl -v https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend
  3. Increase the httpClient timeout and retry with backoff on transient errors
  4. Ensure no proxy env vars (HTTP_PROXY/HTTPS_PROXY) interfere with api.dingtalk.com

Example fix

// before
client := &http.Client{Timeout: 5 * time.Second}
// after
client := &http.Client{Timeout: 30 * time.Second}
// plus caller-side retry
var err error
for i := 0; i < 3; i++ { if err = p.SendAudio(ctx, rc, audio, format); err == nil { break }; time.Sleep(time.Duration(1<<i) * time.Second) }
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.DialTimeout("tcp", "api.dingtalk.com:443", 5*time.Second); if err != nil { /* network unavailable */ }

Try / catch

err := p.SendAudio(ctx, rc, audio, format)
if err != nil {
    var ne net.Error
    if errors.As(err, &ne) && ne.Timeout() { /* retry with backoff */ }
    if errors.Is(err, context.Canceled) { /* caller cancelled; don't retry */ }
}

Prevention

When it happens

Trigger: Calling SendAudio when the network to api.dingtalk.com is down, the context is cancelled mid-flight, the HTTP client timeout expires, TLS fails, or a proxy/firewall blocks the connection.

Common situations: Offline or restricted hosts, slow networks timing out during send, VPN/proxy interruptions, upstream engine cancelling the context.

Related errors


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