{"record":{"id":"4c2aa9491367f183","repo":"chenhg5/cc-connect","slug":"tuitui-invalid-session-key-q","errorCode":null,"errorMessage":"tuitui: invalid session key %q","messagePattern":"tuitui: invalid session key %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/tuitui/tuitui.go","lineNumber":269,"sourceCode":"\tmediaType := \"file\"\n\tif isImage {\n\t\tmediaType = \"image\"\n\t}\n\tmediaID, _, err := p.uploadMedia(ctx, file.Data, file.MimeType, name, mediaType)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"tuitui: upload file: %w\", err)\n\t}\n\trctx, err := requireReplyContext(replyCtx)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn p.sendMediaID(ctx, rctx, mediaID, name, isImage)\n}\n\nfunc (p *Platform) ReconstructReplyCtx(sessionKey string) (any, error) {\n\tparts := strings.SplitN(sessionKey, \":\", 3)\n\tif len(parts) < 2 || parts[0] != \"tuitui\" {\n\t\treturn nil, fmt.Errorf(\"tuitui: invalid session key %q\", sessionKey)\n\t}\n\tchatID := parts[1]\n\tif chatID == \"\" {\n\t\treturn nil, fmt.Errorf(\"tuitui: invalid session key %q\", sessionKey)\n\t}\n\treturn replyContext{chatID: chatID, chatType: guessChatType(chatID)}, nil\n}\n\nfunc (p *Platform) FormattingInstructions() string {\n\treturn `Formatting rules for TuiTui:\n- Plain Markdown is accepted in group text messages and teams/channel messages.\n- For group chats, use standard Markdown in normal text replies; do not ask for\n  page/card messages unless a folded article-style message is explicitly wanted.\n- Keep tables short; prefer concise lists for mobile chat readability.\n\nTuiTui history tools:\n- When the user message includes a ` + \"`Recent TuiTui messages`\" + ` block, treat it as\n  authoritative recent chat context captured by cc-connect. If that injected","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/tuitui/tuitui.go#L251-L287","documentation":"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.","triggerScenarios":"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\".","commonSituations":"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.","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."],"exampleFix":"// before\nrctx, err := p.ReconstructReplyCtx(session.Key) // \"feishu:ou_123\"\n// after\nif !strings.HasPrefix(session.Key, \"tuitui:\") {\n    return fmt.Errorf(\"session %s does not belong to tuitui\", session.Key)\n}\nrctx, err := p.ReconstructReplyCtx(session.Key)","handlingStrategy":"validation","validationCode":"if !strings.HasPrefix(sessionKey, \"tuitui:\") {\n    return fmt.Errorf(\"key %q is not a tuitui session key\", sessionKey)\n}","typeGuard":"func isTuituiKey(k string) bool {\n    parts := strings.SplitN(k, \":\", 2)\n    return len(parts) == 2 && parts[0] == \"tuitui\" && parts[1] != \"\"\n}","tryCatchPattern":"rctx, err := p.ReconstructReplyCtx(key)\nif err != nil {\n    return fmt.Errorf(\"cannot resume session %q: %w\", key, err)\n}","preventionTips":["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."],"tags":["session","parsing","identifier"],"backgroundTag":"invalid-identifier-format","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}