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 injectedView on GitHub (pinned to 4000b2338a)
Solutions
- Pass the original session key exactly as produced by the TuiTui platform (starts with "tuitui:").
- Check where the key was persisted/retrieved; filter sessions by platform before calling ReconstructReplyCtx.
- 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
- Namespace session keys by platform and route by prefix.
- Filter persisted sessions by platform type before resuming.
- Validate key format at persistence time, not just read time.
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
- googlechat: invalid session key %q
- max: cannot reconstruct reply ctx from %q
- webex: cannot reconstruct reply ctx from %q
- acp: session/new: %w
- acp: session/new: empty sessionId
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/4c2aa9491367f183.
Report an issue: GitHub.