{"record":{"id":"63e07922caf4689f","repo":"chenhg5/cc-connect","slug":"tuitui-s-response-exceeds-d-bytes","errorCode":null,"errorMessage":"tuitui: %s response exceeds %d bytes","messagePattern":"tuitui: (.+?) response exceeds (.+?) bytes","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/tuitui/tuitui.go","lineNumber":726,"sourceCode":"\tq.Set(\"appid\", p.appID)\n\tq.Set(\"secret\", p.appSecret)\n\tu.RawQuery = q.Encode()\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), bytes.NewReader(data))\n\tif err != nil {\n\t\treturn err\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := p.client.Do(req)\n\tif err != nil {\n\t\treturn errorsRedacted(err, p.appSecret)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, maxJSONResponseBytes+1))\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(body) > maxJSONResponseBytes {\n\t\treturn fmt.Errorf(\"tuitui: %s response exceeds %d bytes\", apiPath, maxJSONResponseBytes)\n\t}\n\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\treturn fmt.Errorf(\"HTTP %d: %s\", resp.StatusCode, body)\n\t}\n\tvar apiResp struct {\n\t\tErrCode int    `json:\"errcode\"`\n\t\tErrMsg  string `json:\"errmsg\"`\n\t}\n\tif out != nil {\n\t\tif err := json.Unmarshal(body, out); err != nil {\n\t\t\treturn fmt.Errorf(\"tuitui: decode %s response: %w (body_len=%d)\", apiPath, err, len(body))\n\t\t}\n\t\treturn nil\n\t}\n\tif len(bytes.TrimSpace(body)) == 0 {\n\t\treturn nil\n\t}\n\tif err := json.Unmarshal(body, &apiResp); err != nil {","sourceCodeStart":708,"sourceCodeEnd":744,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/tuitui/tuitui.go#L708-L744","documentation":"postJSON caps API responses at maxJSONResponseBytes by reading LimitReader(size+1). If more bytes than the cap arrive, the response is treated as malformed/untrusted and rejected instead of being parsed. This protects memory from runaway responses.","triggerScenarios":"Any postJSON caller (history fetch, getChannelInfo, reactToMessage, sendPayload) receiving a Tuitui API response body larger than maxJSONResponseBytes.","commonSituations":"Fetching channel/direct history for chats with huge accumulated messages; a misbehaving proxy returning huge HTML error pages; API version change inflating response payloads.","solutions":["Reduce the requested page size/limit in the history fetch request so the response fits the cap.","Raise maxJSONResponseBytes if legitimately large responses are expected in your deployment.","Inspect what endpoint returns the oversized body (the %s in the message) and paginate instead of one large call.","Check for a proxy/gateway returning unexpected huge bodies and fix the network path."],"exampleFix":"// before\nresp := p.fetchChannelHistory(ctx, rctx, limit: 500) // > maxJSONResponseBytes\n// after\nresp := p.fetchChannelHistory(ctx, rctx, limit: 50) // paginate in a loop","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := p.postJSON(ctx, path, req, &out); err != nil {\n    if isOversizeErr(err) {\n        return p.paginatedFetch(ctx, rctx) // smaller pages\n    }\n    return err\n}","preventionTips":["Request small page sizes for history endpoints","Keep maxJSONResponseBytes large enough for expected payloads","Monitor for proxies injecting large non-JSON bodies"],"tags":["http","limits","tuitui"],"backgroundTag":"payload-too-large","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}