larksuite/cli · error

connection check: decode: %w (body=%s)

Error message

connection check: decode: %w (body=%s)

What it means

After the connection-check API responds, CheckRemoteConnections decodes the body into a struct with code/msg/data.online_instance_cnt. If json.Unmarshal fails, the error is wrapped as 'connection check: decode: %w (body=%s)' and the (length-bounded, control-character-defanged) raw body is embedded for diagnosis. This means the endpoint was reachable but the payload was not the expected JSON shape.

Source

Thrown at internal/event/consume/remote_preflight.go:30

)

type APIClient = event.APIClient

// CheckRemoteConnections returns the count of active WebSocket connections for this app.
func CheckRemoteConnections(ctx context.Context, client APIClient) (int, error) {
	raw, err := client.CallAPI(ctx, "GET", "/open-apis/event/v1/connection", nil)
	if err != nil {
		return 0, fmt.Errorf("connection check: %w", err)
	}
	var result struct {
		Code int    `json:"code"`
		Msg  string `json:"msg"`
		Data struct {
			OnlineInstanceCnt int `json:"online_instance_cnt"`
		} `json:"data"`
	}
	if err := json.Unmarshal(raw, &result); err != nil {
		return 0, fmt.Errorf("connection check: decode: %w (body=%s)", err, truncateForError(raw))
	}
	// Distinguish "verified zero" from "check failed" — non-zero code decodes Cnt=0.
	if result.Code != 0 {
		return 0, fmt.Errorf("connection check: api error code=%d msg=%q", result.Code, result.Msg)
	}
	return result.Data.OnlineInstanceCnt, nil
}

// truncateForError bounds length and collapses control chars to defang log injection.
func truncateForError(b []byte) string {
	const max = 256
	s := event.TruncateDiagnostic(string(b), max, "…(truncated)")
	out := make([]byte, 0, len(s))
	for _, r := range s {
		if r == '\n' || r == '\r' || r == '\t' {
			out = append(out, ' ')
			continue
		}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Read the embedded body= snippet in the error to see what was actually returned (HTML? empty? partial JSON?).
  2. Verify the base URL points at the official open domain and that no proxy is rewriting responses.
  3. Retry the request; if the body is consistently truncated, check for intermediary proxies or MTU/timeout issues.
  4. Confirm the API contract still matches {code,msg,data.online_instance_cnt} and update the struct if the service schema changed.
Defensive patterns

Strategy: validation

Validate before calling

// Validate the raw response looks like the expected JSON envelope before decoding
var peek struct {
	Code *int `json:"code"`
}
if err := json.Unmarshal(raw, &peek); err != nil || peek.Code == nil {
	// not the expected schema: log truncateForError(raw) and abort/retry
}

Try / catch

_, err := consume.CheckRemoteConnections(ctx, client)
if err != nil {
	var decErr *json.UnmarshalError
	if errors.As(err, &decErr) || strings.Contains(err.Error(), "decode:") {
		// body was not JSON: dump body snippet, retry or fall back
	}
}

Prevention

When it happens

Trigger: json.Unmarshal of the CallAPI response body fails: HTML error/interstitial pages, empty body, truncation, wrong Content-Type gateway responses, or a proxy returning non-JSON text on GET /open-apis/event/v1/connection.

Common situations: Gateway/WAF returning an HTML 502 page, captive portal or proxy intercepting the request, API version change altering the response schema, response body cut off mid-JSON.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/0eb3745ae48ad437. Report an issue: GitHub.