{"record":{"id":"51c6f7dac7f0e122","repo":"chenhg5/cc-connect","slug":"invalid-session-key-format-q","errorCode":null,"errorMessage":"invalid session key format: %q","messagePattern":"invalid session key format: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/relay.go","lineNumber":345,"sourceCode":"\treturn fmt.Sprintf(\"[%s] %s\", toName, truncateRelay(response, 2000))\n}\n\nfunc (rm *RelayManager) relayContext(ctx context.Context) (context.Context, context.CancelFunc) {\n\trm.mu.RLock()\n\ttimeout := rm.timeout\n\trm.mu.RUnlock()\n\tif timeout <= 0 {\n\t\treturn ctx, func() {}\n\t}\n\treturn context.WithTimeout(ctx, timeout)\n}\n\nfunc parseSessionKeyParts(sessionKey string) (platform, chatID string, err error) {\n\t// Format: \"platform:chatID:userID\"\n\t// Relay session format: \"relay:sourceProject:chatID\"\n\tparts := strings.SplitN(sessionKey, \":\", 3)\n\tif len(parts) < 2 {\n\t\treturn \"\", \"\", fmt.Errorf(\"invalid session key format: %q\", sessionKey)\n\t}\n\tif parts[0] == \"relay\" && len(parts) == 3 {\n\t\t// For relay sessions, chatID is the third part: \"relay:sourceProject:chatID\"\n\t\treturn parts[0], parts[2], nil\n\t}\n\treturn parts[0], parts[1], nil\n}\n\n// resolveGroupVisibilityKey computes the session key used for relay\n// visibility echoes.  It defaults to \"<platform>:<chatID>:relay\" and\n// gives the caller's platform a chance to override via the optional\n// core.RelayGroupVisibilityTarget interface.\n//\n// Looking the platform up via sourceEngine.platforms (not targetEngine)\n// matches the existing sendToGroup() resolution path — the visibility\n// echo is dispatched as the source bot, so the source engine's\n// platform impl is authoritative for the key format.\nfunc (rm *RelayManager) resolveGroupVisibilityKey(platform, chatID, callerSessionKey string, sourceEngine *Engine) string {","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/relay.go#L327-L363","documentation":"parseSessionKeyParts (core/relay.go:345) throws this when the session key splits into fewer than 2 colon-separated parts. Valid formats are 'platform:chatID:userID' or 'relay:sourceProject:chatID'; a bare string with no ':' cannot identify a platform/chat.","triggerScenarios":"Passing an empty string, a bare chatID like 'oc_abc123', a session key built without the platform prefix, or a malformed key such as 'feishu' to parseSessionKeyParts via Send, cmdBind, or relayContextForSourceSessionKey.","commonSituations":"Constructing session keys manually in tests or scripts and forgetting the platform prefix; storing only the chatID in a database and passing it as the full key; empty SessionKey field in a RelayRequest or /bind command payload.","solutions":["Format the key as 'platform:chatID:userID' (e.g. 'feishu:oc_abc:ou_123') before passing it","For relay-originated sessions use 'relay:sourceProject:chatID'","Validate the key contains at least one ':' before calling Send/cmdBind","Use the engine's real session key (from the incoming message context) instead of a hand-built one"],"exampleFix":"// before\nrm.Send(ctx, core.RelayRequest{SessionKey: \"oc_abc123\", ...})\n// after\nrm.Send(ctx, core.RelayRequest{SessionKey: \"feishu:oc_abc123:ou_456\", ...})","handlingStrategy":"validation","validationCode":"func validSessionKey(k string) bool {\n\treturn len(strings.SplitN(k, \":\", 3)) >= 2\n}\nif !validSessionKey(req.SessionKey) { return errors.New(\"session key must be platform:chatID[:userID] or relay:sourceProject:chatID\") }","typeGuard":"func asSessionKey(parts ...string) (string, bool) {\n\tif len(parts) < 2 { return \"\", false }\n\tfor _, p := range parts { if p == \"\" { return \"\", false } }\n\treturn strings.Join(parts, \":\"), true\n}","tryCatchPattern":"resp, err := rm.Send(ctx, req)\nif err != nil {\n\tif strings.Contains(err.Error(), \"invalid session key\") || strings.Contains(err.Error(), \"invalid session key format\") {\n\t\treply(\"Internal error: malformed session key \"+req.SessionKey)\n\t\treturn\n\t}\n\treturn err\n}","preventionTips":["Never store bare chatIDs where a full session key is expected — persist the platform prefix","Use a helper to build session keys instead of string concatenation","Assert key shape in tests for any code that constructs RelayRequest or /bind payloads"],"tags":["relay","session-key","parsing"],"backgroundTag":"invalid-argument-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"}