{"record":{"id":"7a476dc736c8bb32","repo":"chenhg5/cc-connect","slug":"bridge-invalid-session-key-q","errorCode":null,"errorMessage":"bridge: invalid session key %q","messagePattern":"bridge: invalid session key %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/bridge.go","lineNumber":464,"sourceCode":"\t}\n\tpayload := bridgeReconstructReplyCtxPayload{\n\t\tKind:                bridgeReconstructReplyCtxKind,\n\t\tVersion:             1,\n\t\tSenderProject:       project,\n\t\tTransportChatID:     chatID,\n\t\tTransportSessionKey: sessionKey,\n\t}\n\tdata, err := json.Marshal(payload)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"bridge: marshal reconstruct reply ctx: %w\", err)\n\t}\n\treturn string(data), nil\n}\n\nfunc bridgeTransportChatID(sessionKey string) (string, error) {\n\tparts := strings.SplitN(sessionKey, \":\", 3)\n\tif len(parts) < 2 || parts[1] == \"\" {\n\t\treturn \"\", fmt.Errorf(\"bridge: invalid session key %q\", sessionKey)\n\t}\n\treturn parts[1], nil\n}\n\nfunc (bp *BridgePlatform) SendCard(ctx context.Context, replyCtx any, card *Card) error {\n\trc, ok := replyCtx.(*bridgeReplyCtx)\n\tif !ok {\n\t\treturn fmt.Errorf(\"bridge: invalid reply context\")\n\t}\n\ta := bp.server.getAdapter(rc.Platform)\n\tif a == nil || !a.capabilities[\"card\"] {\n\t\treturn bp.Reply(ctx, replyCtx, card.RenderText())\n\t}\n\treturn bp.server.sendToAdapter(rc.Platform, map[string]any{\n\t\t\"type\":        \"card\",\n\t\t\"session_key\": rc.SessionKey,\n\t\t\"reply_ctx\":   rc.ReplyCtx,\n\t\t\"card\":        serializeCard(card),","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/bridge.go#L446-L482","documentation":"bridgeTransportChatID splits a session key on ':' and requires at least two parts with a non-empty second segment (the transport chat ID). Keys that are too short or have an empty chat-ID component are rejected with this error while building a reconstruct reply context.","triggerScenarios":"Calling ReconstructReplyCtx (which internally calls buildBridgeReconstructReplyCtx → bridgeTransportChatID) with a malformed session key such as \"bridge:\" or \"feishu:\" — empty, missing segments, or only the adapter prefix.","commonSituations":"Database rows where the session key column was never populated; keys built by string concatenation that dropped the chat ID; legacy keys from an older key format before a version migration.","solutions":["Print the session key and confirm it matches the expected \"prefix:chatID[:extra]\" shape before calling.","Fix the producer of the key (session manager / persistence layer) so it always stores the full key.","Add a migration/validator for stored keys and skip or repair rows with empty chat-ID segments."],"exampleFix":"// before\nreplyCtx, err := bp.ReconstructReplyCtx(strings.ToUpper(key)) // mangling/format drift\n\n// after\nif strings.Count(key, \":\") < 1 { return fmt.Errorf(\"stored key %q malformed\", key) }\nreplyCtx, err := bp.ReconstructReplyCtx(key)","handlingStrategy":"validation","validationCode":"func keyHasChatID(key string) bool {\n    parts := strings.SplitN(key, \":\", 3)\n    return len(parts) >= 2 && parts[1] != \"\"\n}","typeGuard":null,"tryCatchPattern":"if !keyHasChatID(key) { return fmt.Errorf(\"stored key %q missing chat ID\", key) }\nrc, err := bp.ReconstructReplyCtx(key)\nif err != nil { return err }","preventionTips":["Validate session key shape at write time in your persistence layer.","Migrate legacy keys from old formats explicitly.","Treat empty key columns as data bugs, not empty optional values."],"tags":["go","session-key","format"],"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"}