{"record":{"id":"53820032e0e2fd90","repo":"chenhg5/cc-connect","slug":"qq-invalid-session-key-q","errorCode":null,"errorMessage":"qq: invalid session key %q","messagePattern":"qq: invalid session key %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/qq/qq.go","lineNumber":649,"sourceCode":"\tvar result map[string]any\n\t_ = json.Unmarshal(apiResp.Data, &result)\n\treturn result, nil\n}\n\n// ── Helpers ─────────────────────────────────────────────────────\n\ntype replyContext struct {\n\tmessageType string // \"private\" or \"group\"\n\tuserID      int64\n\tgroupID     int64\n\tmessageID   int32\n}\n\nfunc (p *Platform) ReconstructReplyCtx(sessionKey string) (any, error) {\n\t// qq:{userID}, qq:{groupID}:{userID} or qq:g:{groupID}\n\tparts := strings.SplitN(sessionKey, \":\", 3)\n\tif len(parts) < 2 || parts[0] != \"qq\" {\n\t\treturn nil, fmt.Errorf(\"qq: invalid session key %q\", sessionKey)\n\t}\n\tif len(parts) == 3 {\n\t\tif parts[1] == \"g\" {\n\t\t\tgid, _ := strconv.ParseInt(parts[2], 10, 64)\n\t\t\treturn &replyContext{messageType: \"group\", groupID: gid}, nil\n\t\t}\n\t\tgid, _ := strconv.ParseInt(parts[1], 10, 64)\n\t\tuid, _ := strconv.ParseInt(parts[2], 10, 64)\n\t\treturn &replyContext{messageType: \"group\", groupID: gid, userID: uid}, nil\n\t}\n\tuid, _ := strconv.ParseInt(parts[1], 10, 64)\n\treturn &replyContext{messageType: \"private\", userID: uid}, nil\n}\n\nfunc (p *Platform) isAllowed(userID int64) bool {\n\tif p.allowFrom == \"\" || p.allowFrom == \"*\" {\n\t\treturn true\n\t}","sourceCodeStart":631,"sourceCodeEnd":667,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qq/qq.go#L631-L667","documentation":"ReconstructReplyCtx returns this when the supplied sessionKey is not a valid QQ session key. Valid formats are `qq:{userID}`, `qq:{groupID}:{userID}`, or `qq:g:{groupID}`; anything not starting with the `qq:` prefix or with fewer than 2 colon-separated parts is rejected. This guards the reply-context reconstruction path against malformed or foreign session keys.","triggerScenarios":"Passing a session key from another platform (e.g. `feishu:...`, `telegram:123`), an empty string, or a key with a missing prefix/ID component to ReconstructReplyCtx.","commonSituations":"Storing session keys across multiple platforms in one store and replaying a non-QQ key; truncating a key before persistence; schema/serialization change dropping the prefix; hand-editing session data.","solutions":["Print/log the offending sessionKey in the error and fix how it was generated or persisted.","Only pass keys originally produced by this platform's session-key builder (qq:...).","Namespace stored session keys by platform so QQ keys are never mixed with others.","Validate the key format at persistence time (prefix check) to fail early."],"exampleFix":"// before\nctx, err := p.ReconstructReplyCtx(key) // key may be from another platform\n// after\nif !strings.HasPrefix(key, \"qq:\") {\n    return fmt.Errorf(\"not a qq session key: %q\", key)\n}\nctx, err := p.ReconstructReplyCtx(key)","handlingStrategy":"validation","validationCode":"// Go\nfunc isQQSessionKey(k string) bool {\n    parts := strings.SplitN(k, \":\", 3)\n    return len(parts) >= 2 && parts[0] == \"qq\"\n}\n// call before ReconstructReplyCtx\nif !isQQSessionKey(key) { return fmt.Errorf(\"not a qq session key: %q\", key) }","typeGuard":"func validQQSessionKey(k string) bool {\n    p := strings.SplitN(k, \":\", 3)\n    return len(p) >= 2 && p[0] == \"qq\"\n}","tryCatchPattern":"ctx, err := p.ReconstructReplyCtx(key)\nif err != nil {\n    // treat as foreign/corrupt key: skip or rebuild the session context\n    return nil\n}","preventionTips":["Namespace persisted session keys by platform so only qq: keys reach this API.","Round-trip test keys through the session-key builder before storing them.","Never truncate or hand-edit stored session keys."],"tags":["qq","session-key","format-validation"],"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"}