{"record":{"id":"839d9ee84c041c03","repo":"chenhg5/cc-connect","slug":"slack-invalid-reply-context-type-t-839d9e","errorCode":null,"errorMessage":"slack: invalid reply context type %T","messagePattern":"slack: invalid reply context type %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/slack/streaming_card.go","lineNumber":55,"sourceCode":"\tclient   *slack.Client\n\tchannel  string\n\tthreadTS string\n\n\tmu         sync.Mutex\n\tts         string // empty until the first post\n\tfailed     bool\n\tlastUpdate time.Time\n\tlastSent   string\n}\n\n// CreateStreamingCard prepares a lazy streaming card; the Slack message is not\n// posted until the first content arrives. Implements core.StreamingCardPlatform\n// — when present, the engine routes the whole turn through this card and skips\n// the plain streaming preview (mutually exclusive, so no double-post).\nfunc (p *Platform) CreateStreamingCard(ctx context.Context, rctx any) (core.StreamingCard, 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\treturn &slackStreamingCard{client: p.client, channel: rc.channel, threadTS: rc.timestamp}, nil\n}\n\n// postFresh posts a brand-new message — the lazy first post for an unseen\n// card, or the \"too long for chat.update\" overflow path used by Finalize.\n// Caller must hold c.mu.\nfunc (c *slackStreamingCard) postFresh(ctx context.Context, rendered string) (string, error) {\n\topts := []slack.MsgOption{slack.MsgOptionText(rendered, false)}\n\tif c.threadTS != \"\" {\n\t\topts = append(opts, slack.MsgOptionPostMessageParameters(slack.PostMessageParameters{ThreadTimestamp: c.threadTS}))\n\t}\n\t_, ts, err := c.client.PostMessageContext(ctx, c.channel, opts...)\n\treturn ts, err\n}\n\n// render posts the card on first use, then edits it in place thereafter.\n// Caller must hold c.mu.","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/slack/streaming_card.go#L37-L73","documentation":"CreateStreamingCard implements core.StreamingCardPlatform and asserts the reply context is the Slack-internal replyContext struct. This error is returned when any other type is passed — an internal contract violation between the engine and the Slack adapter, meaning the card would be posted with an unknown destination.","triggerScenarios":"The engine invokes CreateStreamingCard with a reply context built by another platform, a nil context, or a test fixture of the wrong type, so the type assertion rctx.(replyContext) fails.","commonSituations":"Session created under one platform but resumed with the Slack platform after config edits; core/adapter version skew; unit tests passing raw structs instead of replyContext.","solutions":["Ensure the turn's session belongs to the Slack platform (check config.toml platform binding)","Recreate the session so the reply context is built by the Slack adapter","Build core and platform/slack from the same source tree","In tests, construct the context via p.ReconstructReplyCtx(\"slack:C...\") or replyContext literals"],"exampleFix":"// before\ncard, err := p.CreateStreamingCard(ctx, \"slack:C123\") // string, not replyContext\n// after\nrc, _ := p.ReconstructReplyCtx(\"slack:C123\")\ncard, err := p.CreateStreamingCard(ctx, rc)","handlingStrategy":"type-guard","validationCode":"rc, ok := rctx.(replyContext)\nif !ok { return fmt.Errorf(\"slack: invalid reply context type %T\", rctx) }","typeGuard":"func isSlackReplyCtx(v any) bool { _, ok := v.(replyContext); return ok }","tryCatchPattern":"card, err := p.CreateStreamingCard(ctx, rctx)\nif err != nil {\n    slog.Warn(\"slack: streaming card unavailable, using plain preview\", \"err\", err)\n    return nil // engine falls back to plain streaming\n}","preventionTips":["Keep each session pinned to one platform adapter","Source reply contexts from the Slack adapter only","Run engine and adapter integration tests on the same build","Return nil from CreateStreamingCard paths early on foreign contexts"],"tags":["slack","type-mismatch","streaming-card","contract"],"backgroundTag":"type-mismatch","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"}