larksuite/cli · error
user_info API returned HTTP %d
Error message
user_info API returned HTTP %d
What it means
fetchUserInfo (for the authen/v1/user_info endpoint, called from enrichUserInfo) requires HTTP 200; any other status aborts with this plain error before decoding JSON. It signals the user-info HTTP call itself failed at the transport/gateway level, not an API-level business error.
Source
Thrown at internal/credential/user_info.go:38
// fetchUserInfo calls /open-apis/authen/v1/user_info with a UAT to get the user's identity.
func fetchUserInfo(ctx context.Context, httpClient *http.Client, brand core.LarkBrand, uat string) (*userInfo, error) {
ep := core.ResolveEndpoints(brand)
url := ep.Open + "/open-apis/authen/v1/user_info"
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+uat)
resp, err := httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("user_info API returned HTTP %d", resp.StatusCode)
}
var result struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
OpenID string `json:"open_id"`
Name string `json:"name"`
} `json:"data"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
if result.Code != 0 {
return nil, fmt.Errorf("user_info API error: [%d] %s", result.Code, result.Msg)
}
return &userInfo{OpenID: result.Data.OpenID, Name: result.Data.Name}, nil
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Check the HTTP status in the message; if 401/403, refresh or re-obtain the user_access_token before calling user_info.
- If 429, add throttling/backoff on user_info calls, especially in bulk enrichment loops.
- If 5xx, retry with backoff and check Lark service status.
- Verify network/proxy configuration if the status is a gateway error (502/504).
Example fix
// before
tok := getStoredUserToken()
info, err := enrichUserInfo(ctx, tok)
// after
info, err := enrichUserInfo(ctx, tok)
if err != nil && strings.Contains(err.Error(), "HTTP 401") {
tok = refreshUserToken(ctx)
info, err = enrichUserInfo(ctx, tok)
} Defensive patterns
Strategy: try-catch
Validate before calling
func ensureUsableUserToken(tok string, fetchedAt time.Time) error {
if tok == "" { return errors.New("missing user access token") }
if time.Since(fetchedAt) > tokenTTL-2*time.Minute { return errors.New("user access token near expiry, refresh first") }
return nil
} Try / catch
info, err := enrichUserInfo(ctx, userToken)
if err != nil {
var statusErr *HTTPStatusError
switch {
case strings.Contains(err.Error(), "HTTP 401"), strings.Contains(err.Error(), "HTTP 403"):
userToken = refreshUserAccessToken(ctx)
info, err = enrichUserInfo(ctx, userToken)
case strings.Contains(err.Error(), "HTTP 429"):
time.Sleep(rateLimitDelay); info, err = enrichUserInfo(ctx, userToken)
}
if err != nil { return err }
} Prevention
- Refresh the user_access_token proactively before it expires rather than on failure.
- Throttle bulk user_info enrichment to avoid 429s.
- Distinguish HTTP-status failures from API-code failures by inspecting the message before retrying.
- Check Lark service status before paging on 5xx-driven occurrences.
When it happens
Trigger: resp.StatusCode != http.StatusOK on the user_info request: 401/403 from an invalid or expired user_access_token, 5xx from the service, 429 rate limiting, or proxy/gateway errors.
Common situations: User access token expired or revoked before the user_info call; tenant misconfig (wrong app credentials so token exchange returns an error page); Lark service incident; rate limiting after bulk user lookups.
Related errors
- failed to get user info [%d]: %s
- failed to get user info: missing open_id in response
- failed to parse response: %w
- Device authorization failed: %s
- failed to verify user identity: %w
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/91a28357f31b672c.
Report an issue: GitHub.