{"record":{"id":"62a481e83bba8111","repo":"chenhg5/cc-connect","slug":"webex-post-chunk-d-d-w","errorCode":null,"errorMessage":"webex: post chunk %d/%d: %w","messagePattern":"webex: post chunk (.+?)/(.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/webex/webex_reply.go","lineNumber":51,"sourceCode":"// Send posts a non-threaded (proactive) message to the room.\nfunc (p *Platform) Send(ctx context.Context, replyCtx any, content string) error {\n\trc, err := asReplyContext(replyCtx)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn p.post(ctx, rc.roomID, \"\", content)\n}\n\n// post chunks content and posts each chunk; only the first chunk threads.\nfunc (p *Platform) post(ctx context.Context, roomID, parentID, content string) error {\n\tchunks := chunkMarkdown(content, webexMaxBytes)\n\tfor i, chunk := range chunks {\n\t\tpid := \"\"\n\t\tif i == 0 {\n\t\t\tpid = parentID\n\t\t}\n\t\tif err := p.client.PostMessage(ctx, roomID, pid, chunk); err != nil {\n\t\t\treturn fmt.Errorf(\"webex: post chunk %d/%d: %w\", i+1, len(chunks), err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// chunkMarkdown splits text to fit within limit bytes, preferring paragraph\n// (\\n\\n), then line (\\n), then a hard cut.\nfunc chunkMarkdown(text string, limit int) []string {\n\tif len(text) <= limit {\n\t\treturn []string{text}\n\t}\n\tvar out []string\n\trest := text\n\tfor len(rest) > limit {\n\t\tcut := strings.LastIndex(rest[:limit], \"\\n\\n\")\n\t\tif cut <= 0 {\n\t\t\tcut = strings.LastIndex(rest[:limit], \"\\n\")\n\t\t}","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/webex/webex_reply.go#L33-L69","documentation":"This error wraps a failure from the Webex REST API when the platform adapter posts one chunk of a multi-chunk reply. Long replies are split by chunkMarkdown into pieces that fit Webex's message size limit, and each chunk is posted sequentially with PostMessage; the index (i+1/len) identifies which chunk failed. The wrapped error from p.client.PostMessage carries the underlying API/network cause.","triggerScenarios":"Reply or Send is called with text long enough to be split into chunks, and PostMessage fails for a non-first chunk — e.g. HTTP 4xx/5xx from Webex (expired token, room deleted, rate limit) or a network failure mid-loop.","commonSituations":"Bot access token expired or revoked mid-conversation; bot removed from the room after the first chunk posted; Webex rate limiting on rapid long replies; transient network outage during a long multi-chunk message.","solutions":["Inspect the wrapped cause (%w) to see the Webex API error code; fix auth or room access accordingly.","Refresh/renew the bot access token if the error indicates 401/invalid token.","Verify the bot is still a member of the target roomID; re-invite if removed.","Implement retry with backoff on the failed chunk (earlier chunks already posted; consider idempotent re-send handling).","Reduce message size or chunk count to lower the chance of hitting rate limits."],"exampleFix":"// before\nif err := p.client.PostMessage(ctx, roomID, pid, chunk); err != nil {\n\treturn fmt.Errorf(\"webex: post chunk %d/%d: %w\", i+1, len(chunks), err)\n}\n// after\nif err := p.client.PostMessage(ctx, roomID, pid, chunk); err != nil {\n\tif isRateLimited(err) {\n\t\ttime.Sleep(backoff(i))\n\t\tif retryErr := p.client.PostMessage(ctx, roomID, pid, chunk); retryErr != nil {\n\t\t\treturn fmt.Errorf(\"webex: post chunk %d/%d (after retry): %w\", i+1, len(chunks), retryErr)\n\t\t}\n\t\tcontinue\n\t}\n\treturn fmt.Errorf(\"webex: post chunk %d/%d: %w\", i+1, len(chunks), err)\n}","handlingStrategy":"try-catch","validationCode":"if len(text) == 0 { return errors.New(\"empty reply text\") } // and check roomID non-empty before calling Send/Reply","typeGuard":"null","tryCatchPattern":"err := platform.Send(ctx, roomID, text)\nif err != nil {\n\tvar apiErr *APIError\n\tif errors.As(err, &apiErr) && apiErr.Code == 401 { refreshToken() }\n\treturn err\n}","preventionTips":["Keep bot tokens refreshed and monitor expiry","Verify bot room membership before long sends","Cap chunk sizes well under the API limit","Add retry with backoff for rate-limit errors"],"tags":["webex","http","api","chunking"],"backgroundTag":"api-request-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}