larksuite/cli · error

HTTP %d

Error message

HTTP %d

What it means

This error means the bot-info endpoint returned HTTP >= 400 but the body either did not parse as a Lark {code,msg} envelope or the envelope carried code 0, so no Lark business code is available. The CLI falls back to reporting only the HTTP status so callers at least know the request failed at the transport/HTTP layer.

Source

Thrown at internal/identitydiag/diagnostics.go:424

	// payload is under "bot", not "data" as the newer Lark API convention.
	var envelope struct {
		Code int    `json:"code"`
		Msg  string `json:"msg"`
		Data struct {
			OpenID  string `json:"open_id"`
			AppName string `json:"app_name"`
		} `json:"bot"`
	}
	parseErr := json.Unmarshal(body, &envelope)

	if resp.StatusCode >= 400 {
		// Lark error responses are usually `{code, msg}` envelopes even on
		// non-2xx — surface them when present so callers see why bot auth
		// was rejected, not just the bare HTTP code.
		if parseErr == nil && envelope.Code != 0 {
			return nil, fmt.Errorf("HTTP %d: [%d] %s", resp.StatusCode, envelope.Code, envelope.Msg)
		}
		return nil, fmt.Errorf("HTTP %d", resp.StatusCode)
	}
	if parseErr != nil {
		return nil, fmt.Errorf("parse response: %w", parseErr)
	}
	if envelope.Code != 0 {
		return nil, fmt.Errorf("[%d] %s", envelope.Code, envelope.Msg)
	}
	if envelope.Data.OpenID == "" {
		return nil, errors.New("open_id is empty")
	}
	return &botInfo{OpenID: envelope.Data.OpenID, AppName: envelope.Data.AppName}, nil
}

func fillTokenFields(id *Identity, token *larkauth.StoredUAToken) {
	id.TokenStatus = larkauth.TokenStatus(token)
	id.Scope = token.Scope
	id.ExpiresAt = formatMillis(token.ExpiresAt)
	id.RefreshExpiresAt = formatMillis(token.RefreshExpiresAt)

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Check the HTTP status in the message: 401/403 point to token problems — refresh credentials; 5xx point to server/gateway issues — retry later.
  2. Verify the resolved Open endpoint URL is correct for the configured brand (no proxy or custom override rewriting it).
  3. Inspect proxy/gateway logs if a corporate proxy sits between the CLI and Lark.
  4. Retry the diagnostics run; if persistent, capture the raw response (verbose/debug logging) and compare against the expected envelope.

Example fix

// before: overridden endpoint points at the wrong host
config: open_api_base_url = "https://internal-gw.example.com"

// after
# remove the override or set the correct Lark open API base
open_api_base_url = "https://open.feishu.cn"
Defensive patterns

Strategy: retry

Try / catch

info, err := fetchBotInfo(ctx, f, cfg, token)
if err != nil {
    if strings.HasPrefix(err.Error(), "HTTP ") && !strings.Contains(err.Error(), "[") {
        // no Lark code available: likely gateway/infra — retry with backoff
        return retry.WithBackoff(ctx, 3, func() error { return fetchBotInfo(ctx, f, cfg, token) })
    }
    return err
}

Prevention

When it happens

Trigger: fetchBotInfo receives a 4xx/5xx response whose body fails envelope parsing (parseErr != nil) or whose envelope.Code == 0 — e.g. an HTML gateway error page or empty body. Reached via diagnoseBot/diagnoseExternalBot.

Common situations: Corporate proxy or gateway returning an HTML 502/503 error page; wrong endpoint URL hitting a non-Lark service; auth sidecar returning a non-JSON body; transient infrastructure errors at the Lark edge.

Related errors


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