MCPcopy
hub / github.com/larksuite/cli / BuildAPIError

Function BuildAPIError

internal/errclass/classify.go:45–165  ·  view source on GitHub ↗

BuildAPIError consumes a parsed Lark API response and returns a typed error. Returns nil when resp is nil or resp["code"] is 0. Routing by Category: Authorization → *errs.PermissionError (with MissingScopes / Identity / ConsoleURL) Authentication → *errs.AuthenticationError Config → *errs.Confi

(resp map[string]any, cc ClassifyContext)

Source from the content-addressed store, hash-verified

43// Unknown Lark codes (LookupCodeMeta returns false) fall back to
44// CategoryAPI + SubtypeUnknown.
45func BuildAPIError(resp map[string]any, cc ClassifyContext) error {
46 if resp == nil {
47 return nil
48 }
49 code := intFromAny(resp["code"])
50 if code == 0 {
51 return nil
52 }
53 msg, _ := resp["msg"].(string)
54 if msg == "" {
55 // Upstream omitted or sent non-string msg. Keep Problem.Message non-empty
56 // so the typed wire envelope still carries a human-readable signal.
57 msg = fmt.Sprintf("API error: [%d]", code)
58 }
59 // Lark API responses sometimes carry log_id at the top level
60 // ({"code":..., "log_id":"..."}) and sometimes nested under "error"
61 // ({"code":..., "error":{"log_id":"..."}}). Prefer top level and fall
62 // back to the nested location so log_id always surfaces on the typed
63 // envelope.
64 logID, _ := resp["log_id"].(string)
65 if logID == "" {
66 if errBlock, ok := resp["error"].(map[string]any); ok {
67 if nested, ok := errBlock["log_id"].(string); ok {
68 logID = nested
69 }
70 }
71 }
72
73 meta, ok := LookupCodeMeta(code)
74 if !ok {
75 meta = CodeMeta{Category: errs.CategoryAPI, Subtype: errs.SubtypeUnknown}
76 }
77
78 base := errs.Problem{
79 Category: meta.Category,
80 Subtype: meta.Subtype,
81 Code: code,
82 Message: msg,
83 LogID: logID,
84 Retryable: meta.Retryable,
85 }
86 // Upstream-provided diagnostic URL (resp.error.troubleshooter). Lifted
87 // universally before the category switch so every classified typed
88 // error surfaces it when present. The remaining contents of resp["error"]
89 // (permission_violations.subject, data.challenge_url, data.hint) are
90 // either lifted into category-specific typed extension fields below or
91 // intentionally dropped as redundant with the typed envelope.
92 if errBlock, ok := resp["error"].(map[string]any); ok {
93 if ts, _ := errBlock["troubleshooter"].(string); ts != "" {
94 base.Troubleshooter = ts
95 }
96 }
97 // Upstream-provided field-level reasons (resp.error.details[].value). Lark
98 // returns these as free-text reason strings with no machine-readable field
99 // name (verified for code 190014:
100 // {"error":{"details":[{"value":"end_time should be later than start_time"}]}}),
101 // so they are lifted into Problem.Hint — the sanctioned free-text recovery
102 // prompt — rather than fabricated structured params. Lifted before the

Calls 7

LookupCodeMetaFunction · 0.85
liftErrorDetailValuesFunction · 0.85
buildPermissionErrorFunction · 0.85
buildConfigErrorFunction · 0.85
buildSecurityPolicyErrorFunction · 0.85
APIHintFunction · 0.85
intFromAnyFunction · 0.70