{"record":{"id":"6b932da8ffda5001","repo":"chenhg5/cc-connect","slug":"slack-send-preview-w","errorCode":null,"errorMessage":"slack: send preview: %w","messagePattern":"slack: send preview: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/slack/streaming.go","lineNumber":37,"sourceCode":"// SendPreviewStart posts the initial streaming-preview message (threaded like a\n// normal reply) and returns a handle for subsequent edits. Implements\n// core.PreviewStarter; together with UpdateMessage it lights up the engine's\n// real-time streaming preview for Slack (the engine throttles the edits, so we\n// stay within chat.update rate limits).\nfunc (p *Platform) SendPreviewStart(ctx context.Context, rctx any, content string) (any, error) {\n\trc, ok := rctx.(replyContext)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"slack: invalid reply context type %T\", rctx)\n\t}\n\topts := []slack.MsgOption{\n\t\tslack.MsgOptionText(core.MarkdownToSlackMrkdwn(content), false),\n\t}\n\tif rc.timestamp != \"\" {\n\t\topts = append(opts, slack.MsgOptionPostMessageParameters(slack.PostMessageParameters{ThreadTimestamp: rc.timestamp}))\n\t}\n\t_, ts, err := p.client.PostMessageContext(ctx, rc.channel, opts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"slack: send preview: %w\", err)\n\t}\n\treturn &slackPreviewHandle{channel: rc.channel, timestamp: ts}, nil\n}\n\n// UpdateMessage edits the preview message in place. The engine passes the handle\n// returned by SendPreviewStart (not the reply context). Implements\n// core.MessageUpdater.\nfunc (p *Platform) UpdateMessage(ctx context.Context, previewHandle any, content string) error {\n\th, ok := previewHandle.(*slackPreviewHandle)\n\tif !ok {\n\t\treturn fmt.Errorf(\"slack: invalid preview handle type %T\", previewHandle)\n\t}\n\t_, _, _, err := p.client.UpdateMessageContext(ctx, h.channel, h.timestamp,\n\t\tslack.MsgOptionText(core.MarkdownToSlackMrkdwn(content), false),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"slack: update preview: %w\", err)\n\t}","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/slack/streaming.go#L19-L55","documentation":"SendPreviewStart posts the initial streaming-preview message via client.PostMessageContext. This error wraps any failure from that Slack Web API call (network error, invalid channel, missing scope, rate limit). The preview message could not be created, so streaming preview is aborted for this turn.","triggerScenarios":"PostMessageContext fails: channel ID invalid or bot not in channel, chat:write scope missing, Slack 429 rate limit, or ctx cancelled before the request completes.","commonSituations":"Bot removed from the channel mid-session; token rotated without reinstalling the app; posting to a thread whose root was deleted; hitting chat.update/chat.postMessage rate limits during heavy streaming.","solutions":["Check the wrapped inner error: rate_limited => backoff and retry; channel_not_found / is_inactive => re-add the bot to the channel","Verify the bot token has chat:write scope","Confirm the channel/thread in the reply context still exists","Inspect network/proxy connectivity to slack.com/api"],"exampleFix":"// before\n// chat:write missing -> PostMessageContext returns invalid_auth\n// after\n// Slack app settings: add chat:write scope, reinstall app, restart cc-connect","handlingStrategy":"fallback","validationCode":"// ensure bot is in channel before streaming\n_, err := p.client.GetConversationInfo(&slack.GetConversationInfoInput{ChannelID: rc.channel, IncludeLocale: false})","typeGuard":null,"tryCatchPattern":"handle, err := p.SendPreviewStart(ctx, rctx, content)\nif err != nil {\n    var rl *slack.RateLimitedError\n    if errors.As(err, &rl) { /* back off and retry once */ }\n    return nil // fall back to a single final reply instead of streaming\n}","preventionTips":["Confirm chat:write scope and bot membership in target channels","Keep engine-side throttling of preview edits enabled","Fall back to non-streaming replies when preview start fails","Watch for 429s and respect Retry-After"],"tags":["slack","api","streaming","message-post"],"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"}