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

  1. Only pass the value returned by SendPreviewStart (as *slackPreviewHandle) to UpdateMessage
  2. Check the SendPreviewStart error before using its handle; skip UpdateMessage on failure
  3. Recreate the session/turn so the handle is produced by the Slack adapter
  4. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/01fc2ee7d2a326b2. Report an issue: GitHub.