{"record":{"id":"478f6de3d60bce1e","repo":"chenhg5/cc-connect","slug":"qqbot-invalid-session-key-q","errorCode":null,"errorMessage":"qqbot: invalid session key %q","messagePattern":"qqbot: invalid session key %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/qqbot/qqbot.go","lineNumber":540,"sourceCode":"// Stop shuts down the platform.\nfunc (p *Platform) Stop() error {\n\tif p.cancel != nil {\n\t\tp.cancel()\n\t}\n\tp.wsMu.Lock()\n\tdefer p.wsMu.Unlock()\n\tif p.wsConn != nil {\n\t\treturn p.wsConn.Close()\n\t}\n\treturn nil\n}\n\n// ReconstructReplyCtx implements core.ReplyContextReconstructor.\n// Session key format: \"qqbot:{group_openid}:{member_openid}\", \"qqbot:g:{group_openid}\" or \"qqbot:{user_openid}\"\nfunc (p *Platform) ReconstructReplyCtx(sessionKey string) (any, error) {\n\tparts := strings.SplitN(sessionKey, \":\", 3)\n\tif len(parts) < 2 || parts[0] != \"qqbot\" {\n\t\treturn nil, fmt.Errorf(\"qqbot: invalid session key %q\", sessionKey)\n\t}\n\tif len(parts) == 3 {\n\t\tif parts[1] == \"g\" {\n\t\t\treturn &replyContext{\n\t\t\t\tmessageType: \"group\",\n\t\t\t\tgroupOpenID: parts[2],\n\t\t\t\tsessionKey:  sessionKey,\n\t\t\t}, nil\n\t\t}\n\t\treturn &replyContext{\n\t\t\tmessageType: \"group\",\n\t\t\tgroupOpenID: parts[1],\n\t\t\tuserOpenID:  parts[2],\n\t\t\tsessionKey:  sessionKey,\n\t\t}, nil\n\t}\n\treturn &replyContext{\n\t\tmessageType: \"c2c\",","sourceCodeStart":522,"sourceCodeEnd":558,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qqbot/qqbot.go#L522-L558","documentation":"ReconstructReplyCtx rebuilds a reply context from a stored session key. Valid formats are \"qqbot:{group_openid}:{member_openid}\" (3 parts), \"qqbot:g:{group_openid}\" (3 parts, group broadcast), or \"qqbot:{user_openid}\" (2 parts, c2c). If the key does not split into at least 2 colon-separated parts with the literal prefix \"qqbot\", this error is returned (platform/qqbot/qqbot.go:540).","triggerScenarios":"Calling ReconstructReplyCtx with a session key from another platform (e.g. \"feishu:oc_xxx\"), an empty/whitespace key, a key without the \"qqbot:\" prefix, or a key like \"qqbot\" with no separator at all.","commonSituations":"Persisted session keys reused after switching the platform adapter; keys stored by an older version with a different format; cron/scheduled jobs referencing sessions of a different platform; hand-edited config pointing a timer at the wrong session key.","solutions":["Check the stored session key starts with \"qqbot:\" and has the right number of colon-separated parts.","If the session belongs to another platform, route it to that platform's ReconstructReplyCtx instead.","Regenerate the session by messaging the bot once and using the fresh key the platform records."],"exampleFix":"// before\nrc, err := qqbotPlatform.ReconstructReplyCtx(\"feishu:oc_123\") // invalid prefix\n// after\nif strings.HasPrefix(key, \"qqbot:\") {\n    rc, err = qqbotPlatform.ReconstructReplyCtx(key)\n} else {\n    rc, err = feishuPlatform.ReconstructReplyCtx(key)\n}","handlingStrategy":"validation","validationCode":"func isQQBotSessionKey(key string) bool {\n    parts := strings.SplitN(key, \":\", 3)\n    return len(parts) >= 2 && parts[0] == \"qqbot\"\n}","typeGuard":null,"tryCatchPattern":"rc, err := p.ReconstructReplyCtx(key)\nif err != nil {\n    slog.Warn(\"cannot reconstruct qqbot reply ctx\", \"key\", core.RedactToken(key), \"err\", err)\n    return nil // skip rather than crash\n}","preventionTips":["Persist the platform name alongside each session key and dispatch to the matching adapter.","Validate session-key format before storing it.","Never hand-edit session keys; regenerate them by interacting with the bot."],"tags":["qqbot","session-key","parsing","invalid-argument-format"],"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"}