chenhg5/cc-connect · error
slack: invalid preview handle type %T
Error message
slack: invalid preview handle type %T
What it means
UpdateMessage edits an existing preview message in place and expects the handle previously returned by SendPreviewStart (*slackPreviewHandle). This error fires when the handle argument has any other type (or is nil) — an engine/adapter contract violation indicating the caller did not thread the handle through correctly.
Source
Thrown at platform/slack/streaming.go:48
slack.MsgOptionText(core.MarkdownToSlackMrkdwn(content), false),
}
if rc.timestamp != "" {
opts = append(opts, slack.MsgOptionPostMessageParameters(slack.PostMessageParameters{ThreadTimestamp: rc.timestamp}))
}
_, ts, err := p.client.PostMessageContext(ctx, rc.channel, opts...)
if err != nil {
return nil, fmt.Errorf("slack: send preview: %w", err)
}
return &slackPreviewHandle{channel: rc.channel, timestamp: ts}, nil
}
// UpdateMessage edits the preview message in place. The engine passes the handle
// returned by SendPreviewStart (not the reply context). Implements
// core.MessageUpdater.
func (p *Platform) UpdateMessage(ctx context.Context, previewHandle any, content string) error {
h, ok := previewHandle.(*slackPreviewHandle)
if !ok {
return fmt.Errorf("slack: invalid preview handle type %T", previewHandle)
}
_, _, _, err := p.client.UpdateMessageContext(ctx, h.channel, h.timestamp,
slack.MsgOptionText(core.MarkdownToSlackMrkdwn(content), false),
)
if err != nil {
return fmt.Errorf("slack: update preview: %w", err)
}
return nil
}
var (
_ core.MessageUpdater = (*Platform)(nil)
_ core.PreviewStarter = (*Platform)(nil)
)
View on GitHub (pinned to 4000b2338a)
Solutions
- Only pass the value returned by SendPreviewStart (as *slackPreviewHandle) to UpdateMessage
- Check the SendPreviewStart error before using its handle; skip UpdateMessage on failure
- Recreate the session/turn so the handle is produced by the Slack adapter
- Rebuild core and platform packages from the same commit to eliminate type skew
Example fix
// before
handle, _ := p.SendPreviewStart(ctx, rc, content) // error ignored
p.UpdateMessage(ctx, handle, more) // handle may be nil
// after
handle, err := p.SendPreviewStart(ctx, rc, content)
if err != nil { return err }
p.UpdateMessage(ctx, handle, more) Defensive patterns
Strategy: type-guard
Validate before calling
h, ok := previewHandle.(*slackPreviewHandle)
if !ok { return fmt.Errorf("slack: invalid preview handle type %T", previewHandle) }
if h == nil { return errors.New("slack: nil preview handle") } Type guard
func asSlackPreviewHandle(v any) (*slackPreviewHandle, bool) { h, ok := v.(*slackPreviewHandle); return h, ok && h != nil } Try / catch
if err := p.UpdateMessage(ctx, handle, content); err != nil {
slog.Warn("slack: preview update skipped", "err", err)
} Prevention
- Always check SendPreviewStart's error before using its handle
- Thread the handle only within the same platform's turn
- Never cache handles across sessions/platform switches
- Compile core+platform together to avoid type skew
When it happens
Trigger: The engine calls UpdateMessage with a handle from a different platform, a stale/nil handle, or the return value of a failed SendPreviewStart call.
Common situations: Platform switched mid-turn so a non-Slack handle reaches UpdateMessage; caller ignored the error from SendPreviewStart and used its nil handle; version skew between core and platform/slack.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- slack: invalid reply context type %T
- slack: invalid reply context type %T
- googlechat: invalid reply context type %T
- slack: send preview: %w
- slack: update preview: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/01fc2ee7d2a326b2.
Report an issue: GitHub.