larksuite/cli · error
response parse error: %w (body: %s)
Error message
response parse error: %w (body: %s)
What it means
ParseJSONResponse decodes the API response RawBody with json.Decoder (UseNumber) and wraps a decode failure with the underlying error plus a 500-char truncated body. It exists so callers see both why parsing failed and what the server actually returned (often an HTML error page or empty/garbled body).
Source
Thrown at internal/client/response.go:199
}
return errs.NewInternalError(errs.SubtypeFileIO, "save response: %v", err).WithCause(err)
}
// ── JSON helpers ──
// IsJSONContentType reports whether the Content-Type header indicates a JSON response.
func IsJSONContentType(ct string) bool {
return strings.Contains(ct, "application/json") || strings.Contains(ct, "text/json")
}
// ParseJSONResponse decodes a raw SDK response body as JSON.
// CallAPI and HandleResponse both delegate to this function.
func ParseJSONResponse(resp *larkcore.ApiResp) (interface{}, error) {
var result interface{}
dec := json.NewDecoder(bytes.NewReader(resp.RawBody))
dec.UseNumber()
if err := dec.Decode(&result); err != nil {
return nil, fmt.Errorf("response parse error: %w (body: %s)", err, util.TruncateStr(string(resp.RawBody), 500))
}
return result, nil
}
// ── File saving ──
// SaveResponse writes an API response body to the given outputPath and returns metadata.
// It delegates to FileIO.Save for path validation and atomic write; fio must not be nil.
func SaveResponse(fio fileio.FileIO, resp *larkcore.ApiResp, outputPath string) (map[string]interface{}, error) {
result, err := fio.Save(outputPath, fileio.SaveOptions{
ContentType: resp.Header.Get("Content-Type"),
ContentLength: int64(len(resp.RawBody)),
}, bytes.NewReader(resp.RawBody))
if err != nil {
var me *fileio.MkdirError
var we *fileio.WriteError
switch {
case errors.Is(err, fileio.ErrPathValidation):View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Inspect the truncated body in the error message to identify what the server returned
- Check for proxy/WAF interception and retry with a direct network path
- Retry the request if it was transient (502/504 gateway pages)
- Verify API endpoint and auth are correct — non-JSON often means an error page
Defensive patterns
Strategy: try-catch
Validate before calling
if !json.Valid(resp.RawBody) {
return fmt.Errorf("non-JSON response (status %d): %.200s", resp.StatusCode, resp.RawBody)
} Try / catch
result, err := ParseJSONResponse(resp)
if err != nil {
var pe *ParseError
if strings.Contains(err.Error(), "response parse error") {
log.Printf("API returned non-JSON body; inspecting truncated payload: %v", err)
// inspect body in message; retry or fall back to raw text
return retryWithBackoff(req)
}
return err
} Prevention
- Check status codes before parsing; gateways often return HTML for 5xx
- Detect and bypass captive portals / corporate proxies in CI
- Log RawBody (truncated) on any parse failure for forensics
- Keep SDK and endpoint versions in sync
When it happens
Trigger: Lark API (or an intermediary) returning non-JSON bodies: HTML error pages from proxies/WAFs, empty responses (EOF), truncated responses, or wrong Content-Type payloads.
Common situations: Corporate proxies or captive portals injecting HTML; rate-limit/gateway pages; server 200 with empty body; SDK version changes altering expected response shape.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to parse response: %w
- app registration failed: HTTP %d – response not JSON
- parse response: %w
- failed to parse user info: %w
- parse range start: %w
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/c98e47338165d478.
Report an issue: GitHub.