{"record":{"id":"a2ad4a27772e915d","repo":"Tencent/WeKnora","slug":"gateway-url-must-use-wss","errorCode":null,"errorMessage":"gateway_url must use wss","messagePattern":"gateway_url must use wss","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/im/qqbot/client.go","lineNumber":101,"sourceCode":"\tif u.Scheme != \"http\" && u.Scheme != \"https\" {\n\t\treturn fmt.Errorf(\"invalid qqbot api_base_url: must use http or https\")\n\t}\n\tif err := secutils.ValidateURLForSSRF(raw); err != nil {\n\t\treturn fmt.Errorf(\"invalid qqbot api_base_url: %w (for private deployments, add the hostname to SSRF_WHITELIST)\", err)\n\t}\n\treturn nil\n}\n\nfunc validateGatewayURL(raw string) error {\n\tif strings.TrimSpace(raw) == \"\" {\n\t\treturn nil\n\t}\n\tu, err := url.Parse(raw)\n\tif err != nil || u.Host == \"\" {\n\t\treturn fmt.Errorf(\"gateway_url must be a valid wss URL\")\n\t}\n\tif u.Scheme != \"wss\" {\n\t\treturn fmt.Errorf(\"gateway_url must use wss\")\n\t}\n\tcheckURL := *u\n\tcheckURL.Scheme = \"https\"\n\tif err := secutils.ValidateURLForSSRF(checkURL.String()); err != nil {\n\t\treturn fmt.Errorf(\n\t\t\t\"gateway_url failed SSRF validation: %w (for private deployments, add the hostname to SSRF_WHITELIST)\",\n\t\t\terr,\n\t\t)\n\t}\n\treturn nil\n}\n\nfunc (c *Client) SendC2CMessage(ctx context.Context, openID, content, msgID string) error {\n\tpath := fmt.Sprintf(\"/v2/users/%s/messages\", openID)\n\treturn c.sendText(ctx, path, content, msgID)\n}\n\nfunc (c *Client) SendGroupMessage(ctx context.Context, groupOpenID, content, msgID string) error {","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/im/qqbot/client.go#L83-L119","documentation":"Validation helper validateGatewayURL rejects a configured QQ bot gateway_url whose scheme is not wss — the gateway requires secure WebSocket. Fires only when an override is provided with ws/https or another scheme.","triggerScenarios":"NewClient or GatewayURL is given a gateway_url whose parsed scheme is not \"wss\", e.g. http:// or ws://.","commonSituations":"Copying an HTTPS API URL into the gateway_url field; using insecure ws:// for local testing; older configs written before wss was enforced.","solutions":["Change the scheme to wss:// (e.g. wss://api.sgroup.qq.com/websocket)","Keep the HTTPS API endpoint in api_base_url, not gateway_url","For local testing against a private gateway, use wss with a locally trusted certificate"],"exampleFix":"// before\ncfg.GatewayURL = \"https://api.sgroup.qq.com/websocket\"\n// after\ncfg.GatewayURL = \"wss://api.sgroup.qq.com/websocket\"","handlingStrategy":"validation","validationCode":"func isWSS(raw string) bool {\n    p, err := url.Parse(strings.TrimSpace(raw))\n    return err == nil && p.Host != \"\" && p.Scheme == \"wss\"\n}\nif !isWSS(cfg.GatewayURL) { return errors.New(\"gateway_url must start with wss://\") }","typeGuard":null,"tryCatchPattern":"client, err := NewClient(cfg)\nif err != nil && strings.Contains(err.Error(), \"gateway_url must use wss\") {\n    return fmt.Errorf(\"gateway scheme must be wss://: %w\", err)\n}","preventionTips":["Never reuse the HTTPS API URL as gateway_url","Enforce scheme in config validation","Prefer letting the client discover the gateway"],"tags":["configuration","websocket","qqbot","scheme"],"backgroundTag":"invalid-url-config","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}