chenhg5/cc-connect · error

slack: invalid session key %q

Error message

slack: invalid session key %q

What it means

ReconstructReplyCtx rebuilds a replyContext from a persisted session key string. The key must be 'slack:{channel}', 'slack:{channel}:{user}', or 'slack:{channel}:t:{threadTS}'. This error is thrown when the string has fewer than two colon-separated parts or does not start with the 'slack' prefix — i.e. the stored key is malformed or belongs to another platform.

Source

Thrown at platform/slack/slack.go:597

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("read response body: %w", err)
	}

	// Basic sanity check: detect if we received HTML instead of binary data
	if len(data) > 0 && (bytes.HasPrefix(data, []byte("<!DOCTYPE")) || bytes.HasPrefix(data, []byte("<html"))) {
		return nil, fmt.Errorf("received HTML response (likely missing auth); first 100 bytes: %s", string(data[:min(100, len(data))]))
	}

	return data, nil
}

func (p *Platform) ReconstructReplyCtx(sessionKey string) (any, error) {
	// slack:{channel}:{user}  |  slack:{channel}:t:{threadTS}  |  slack:{channel}
	parts := strings.SplitN(sessionKey, ":", 3)
	if len(parts) < 2 || parts[0] != "slack" {
		return nil, fmt.Errorf("slack: invalid session key %q", sessionKey)
	}
	rc := replyContext{channel: parts[1]}
	// Thread-scoped keys carry the thread root ts as a "t:<ts>" suffix; preserve
	// it so proactive replies (cron, send-to-session, restart/model/delete
	// notifications) post into the original thread instead of the channel root.
	if len(parts) == 3 && strings.HasPrefix(parts[2], "t:") {
		rc.timestamp = strings.TrimPrefix(parts[2], "t:")
	}
	return rc, nil
}

func (p *Platform) resolveUserName(userID string) string {
	if cached, ok := p.userNameCache.Load(userID); ok {
		return cached.(string)
	}
	user, err := p.client.GetUserInfo(userID)
	if err != nil {
		slog.Debug("slack: resolve user name failed", "user", userID, "error", err)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Print/log the offending key and confirm it matches 'slack:{channel}[:{user}|:t:{threadTS}]'
  2. Delete or re-create the stale session so the engine regenerates a correctly formatted key
  3. Check that the session key was produced by the slack adapter, not another platform
  4. If migrating formats, migrate stored keys to the current scheme before restart

Example fix

// before
cfg.SessionKey = "1234567890" // missing platform prefix
rc, err := p.ReconstructReplyCtx(cfg.SessionKey)
// after
cfg.SessionKey = "slack:C0123456789"
rc, err := p.ReconstructReplyCtx(cfg.SessionKey)
Defensive patterns

Strategy: validation

Validate before calling

func validSlackKey(k string) bool {
    p := strings.SplitN(k, ":", 3)
    return len(p) >= 2 && p[0] == "slack" && p[1] != ""
}
if !validSlackKey(sessionKey) { return errors.New("malformed slack session key") }

Try / catch

rc, err := p.ReconstructReplyCtx(sessionKey)
if err != nil {
    slog.Warn("dropping session with bad key", "key", sessionKey, "err", err)
    return nil // recreate session instead of failing the flow
}

Prevention

When it happens

Trigger: Calling ReconstructReplyCtx with a session key written by a different platform adapter (e.g. 'telegram:123'), an empty string, a truncated key, or a legacy key format saved before the thread 't:' scheme existed.

Common situations: Restoring sessions from an old config/db after switching platforms; hand-editing session keys; a bug in whatever persisted the key; passing a channel name instead of the full key.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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