chenhg5/cc-connect · error

tuitui: invalid session key %q

Error message

tuitui: invalid session key %q

What it means

ReconstructReplyCtx parses a session key expected in the form "tuitui:<chatID>[:...]". If the key has fewer than two colon-separated parts or does not start with the "tuitui" prefix, it cannot belong to this platform and the error reports the offending key. This happens when a session key from another platform (or garbage) is routed to the TuiTui adapter.

Source

Thrown at platform/tuitui/tuitui.go:269

	mediaType := "file"
	if isImage {
		mediaType = "image"
	}
	mediaID, _, err := p.uploadMedia(ctx, file.Data, file.MimeType, name, mediaType)
	if err != nil {
		return fmt.Errorf("tuitui: upload file: %w", err)
	}
	rctx, err := requireReplyContext(replyCtx)
	if err != nil {
		return err
	}
	return p.sendMediaID(ctx, rctx, mediaID, name, isImage)
}

func (p *Platform) ReconstructReplyCtx(sessionKey string) (any, error) {
	parts := strings.SplitN(sessionKey, ":", 3)
	if len(parts) < 2 || parts[0] != "tuitui" {
		return nil, fmt.Errorf("tuitui: invalid session key %q", sessionKey)
	}
	chatID := parts[1]
	if chatID == "" {
		return nil, fmt.Errorf("tuitui: invalid session key %q", sessionKey)
	}
	return replyContext{chatID: chatID, chatType: guessChatType(chatID)}, nil
}

func (p *Platform) FormattingInstructions() string {
	return `Formatting rules for TuiTui:
- Plain Markdown is accepted in group text messages and teams/channel messages.
- For group chats, use standard Markdown in normal text replies; do not ask for
  page/card messages unless a folded article-style message is explicitly wanted.
- Keep tables short; prefer concise lists for mobile chat readability.

TuiTui history tools:
- When the user message includes a ` + "`Recent TuiTui messages`" + ` block, treat it as
  authoritative recent chat context captured by cc-connect. If that injected

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Pass the original session key exactly as produced by the TuiTui platform (starts with "tuitui:").
  2. Check where the key was persisted/retrieved; filter sessions by platform before calling ReconstructReplyCtx.
  3. Recreate the session by letting the platform handle a new incoming message instead of reconstructing from a foreign key.

Example fix

// before
rctx, err := p.ReconstructReplyCtx(session.Key) // "feishu:ou_123"
// after
if !strings.HasPrefix(session.Key, "tuitui:") {
    return fmt.Errorf("session %s does not belong to tuitui", session.Key)
}
rctx, err := p.ReconstructReplyCtx(session.Key)
Defensive patterns

Strategy: validation

Validate before calling

if !strings.HasPrefix(sessionKey, "tuitui:") {
    return fmt.Errorf("key %q is not a tuitui session key", sessionKey)
}

Type guard

func isTuituiKey(k string) bool {
    parts := strings.SplitN(k, ":", 2)
    return len(parts) == 2 && parts[0] == "tuitui" && parts[1] != ""
}

Try / catch

rctx, err := p.ReconstructReplyCtx(key)
if err != nil {
    return fmt.Errorf("cannot resume session %q: %w", key, err)
}

Prevention

When it happens

Trigger: Calling ReconstructReplyCtx with a key like "feishu:ou_123", "", or a string with no colon; also when the prefix before the first colon is not exactly "tuitui".

Common situations: A session persisted under a different platform is resumed after the platform type changed in config; manually constructed or corrupted session keys in a store; key-format version drift after an upgrade.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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