chenhg5/cc-connect · error

wecom-ws: ack timeout waiting for %s

Error message

wecom-ws: ack timeout waiting for %s

What it means

Timeout sentinel surfacing from writeAndWaitAckStrict: the frame with the given req_id was written to the WeCom WebSocket but no server ack arrived within the configured timeout (errWSAckTimeout from writeAndWaitResult). Unlike the non-strict writeAndWaitAck variant, which logs and proceeds, the strict path — used by sendWSMediaMessage where the ack carries the operation result — returns the timeout as a hard error.

Source

Thrown at platform/wecom/websocket.go:593

	return p.writeAndWaitAckWithTimeout(ctx, frame, reqID, wsAckTimeout)
}

func (p *WSPlatform) writeAndWaitAckWithTimeout(ctx context.Context, frame map[string]any, reqID string, timeout time.Duration) error {
	result, err := p.writeAndWaitResult(ctx, frame, reqID, timeout)
	if errors.Is(err, errWSAckTimeout) {
		slog.Debug("wecom-ws: ack timeout, proceeding", "req_id", reqID)
		return nil
	}
	if err != nil {
		return err
	}
	return result.err
}

func (p *WSPlatform) writeAndWaitAckStrict(ctx context.Context, frame map[string]any, reqID string, timeout time.Duration) error {
	result, err := p.writeAndWaitResult(ctx, frame, reqID, timeout)
	if errors.Is(err, errWSAckTimeout) {
		return fmt.Errorf("wecom-ws: ack timeout waiting for %s", reqID)
	}
	if err != nil {
		return err
	}
	return result.err
}

func (p *WSPlatform) writeAndWaitFrameWithTimeout(ctx context.Context, frame map[string]any, reqID string, timeout time.Duration) (wsFrame, error) {
	result, err := p.writeAndWaitResult(ctx, frame, reqID, timeout)
	if errors.Is(err, errWSAckTimeout) {
		return wsFrame{}, fmt.Errorf("wecom-ws: ack timeout waiting for %s", reqID)
	}
	if err != nil {
		return wsFrame{}, err
	}
	if result.err != nil {
		return wsFrame{}, result.err
	}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Retry the media upload once: transient ack loss is common on the long-lived socket
  2. Verify network health and WebSocket keepalive/heartbeat cadence if timeouts recur
  3. Consider whether the strict variant is required — the lenient variant already proceeds on timeout for text frames
  4. Log req_id (already included) to correlate with any late ack and avoid double-sends on manual retry
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at platform/wecom/websocket.go:593 when the library encounters an invalid state.

Common situations: See trigger scenarios.

Understand the failure class


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