larksuite/cli · error
TAT response missing access_token (HTTP %d)
Error message
TAT response missing access_token (HTTP %d)
What it means
The TAT endpoint returned a 2xx response whose parsed JSON contains neither an access_token nor an OAuth error field (code==0 and error=="") — a malformed success. The library treats it as ambiguous/untyped because the HTTP status says success but no token was delivered.
Source
Thrown at internal/credential/tat_fetch.go:126
if result.Code == 0 && result.AccessToken != "" {
return result.AccessToken, nil
}
// Transient/server-side failures stay untyped so probe callers stay silent and
// retryers can back off; only deterministic client rejections are typed. Covers
// 5xx and the OAuth transient error strings (server_error,
// temporarily_unavailable, slow_down). HTTP 429 was already returned above
// as a typed rate-limit error with retry guidance and an upstream delay when available.
if resp.StatusCode >= 500 ||
result.Error == "server_error" || result.Error == "temporarily_unavailable" ||
result.Error == "slow_down" {
return "", fmt.Errorf("TAT endpoint transient failure (HTTP %d, code=%d, error=%q): %s",
resp.StatusCode, result.Code, result.Error, result.ErrorDescription)
}
// A 2xx with neither token nor error is a malformed success — ambiguous, untyped.
if result.Code == 0 && result.Error == "" {
return "", fmt.Errorf("TAT response missing access_token (HTTP %d)", resp.StatusCode)
}
// Prefer the OAuth error_description; fall back to the legacy Lark `msg` so a
// gateway-level {code, msg} response (carrying no OAuth fields) still yields a
// non-empty typed message instead of a bare "API error: [code]".
desc := result.ErrorDescription
if desc == "" {
desc = result.Msg
}
return "", classifyTATResponseCode(result.Code, result.Error, desc, string(brand), appID)
}
func tatRetryAfterSeconds(header http.Header) int {
for _, name := range []string{"X-Ogw-Ratelimit-Reset", "Retry-After"} {
seconds, err := strconv.Atoi(strings.TrimSpace(header.Get(name)))
if err == nil && seconds > 0 {
return seconds
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Log the full 2xx response body and headers to identify what actually came back instead of an access_token.
- Verify you are calling the current, documented TAT/OAuth token endpoint path and version.
- Retry once in case of an intermittent upstream issue; if reproducible, report the malformed response shape to the API provider.
- Check whether a proxy or response-rewriting middleware is stripping or altering the JSON payload.
Example fix
// before (assumes token present whenever err==nil)
// after (fail fast and dump body when token is missing)
if resp.StatusCode == 200 && !strings.Contains(string(body), "access_token") {
log.Fatalf("unexpected 2xx TAT body: %s", string(body))
} Defensive patterns
Strategy: fallback
Type guard
func isMalformedSuccess(err error) bool {
return strings.Contains(err.Error(), "TAT response missing access_token")
} Try / catch
token, err := credential.FetchTAT(ctx, cfg)
if err != nil {
if strings.Contains(err.Error(), "TAT response missing access_token") {
// HTTP said 2xx but no token: capture body, retry once, then escalate
log.Printf("malformed TAT success, retrying once")
token, err = credential.FetchTAT(ctx, cfg)
}
if err != nil { return err }
} Prevention
- Pin to current API endpoint paths and upgrade SDK/metadata when the provider changes token response shapes.
- Log full response bodies on this error to enable upstream bug reports.
- Check middleware/proxies that might strip or rewrite JSON response fields.
- Keep a regression test decoding the real token endpoint response shape in CI against a recorded fixture.
When it happens
Trigger: A 2xx response with {code:0} but no access_token field, or an empty/other-shaped JSON body that unmarshals into zero fields, from the token endpoint.
Common situations: Upstream schema change on the token endpoint (fields renamed/removed); a misconfigured endpoint (e.g. wrong path) returning a benign empty JSON success; an intermediary caching or rewriting the response body.
Related errors
- failed to parse TAT response (HTTP %d): %w
- failed to parse response: %w
- content-range is empty
- unsupported content-range: %q
- unknown total size in content-range: %q
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/d31ea22a7be91629.
Report an issue: GitHub.