{"record":{"id":"3550d323415c18ff","repo":"XTLS/Xray-core","slug":"vless-users-inbound-s-reverse-can-t-have-sniff","errorCode":null,"errorMessage":"VLESS users: inbound's \"reverse\" can't have \"sniffing\"","messagePattern":"VLESS users: inbound's \"reverse\" can't have \"sniffing\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/vless.go","lineNumber":93,"sourceCode":"\t\tcase vless.XRV:\n\t\tdefault:\n\t\t\treturn errors.New(`VLESS users: \"flow\" doesn't support \"` + account.Flow + `\" in this version`)\n\t\t}\n\n\t\tif len(account.Testseed) < 4 {\n\t\t\taccount.Testseed = c.Testseed\n\t\t}\n\n\t\tif account.Encryption != \"\" {\n\t\t\treturn errors.New(`VLESS users: \"encryption\" should not be in inbound settings`)\n\t\t}\n\n\t\tif account.Reverse != nil {\n\t\t\tif account.Reverse.Tag == \"\" {\n\t\t\t\treturn errors.New(`VLESS users: \"tag\" can't be empty for \"reverse\"`)\n\t\t\t}\n\t\t\tif account.Reverse.Sniffing != nil { // may not be reached: error json unmarshal\n\t\t\t\treturn errors.New(`VLESS users: inbound's \"reverse\" can't have \"sniffing\"`)\n\t\t\t}\n\t\t}\n\n\t\tuser.Account = serial.ToTypedMessage(account)\n\t\tconfig.Users[idx] = user\n\t\treturn nil\n\t}\n\n\tif err := task.ParallelForN(len(c.Users), processClient); err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfig.Decryption = c.Decryption\n\tif !func() bool {\n\t\ts := strings.Split(config.Decryption, \".\")\n\t\tif len(s) < 4 || s[0] != \"mlkem768x25519plus\" {\n\t\t\treturn false\n\t\t}","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/vless.go#L75-L111","documentation":"If a VLESS inbound user's 'reverse' object carries a 'sniffing' field, the config is rejected — sniffing is an inbound-level (stream-level) setting, not a per-user reverse option. The source comment notes this branch may be unreachable because JSON unmarshal may already fail, but the guard exists for safety.","triggerScenarios":"\"reverse\": { \"tag\": \"bridge\", \"sniffing\": { \"enabled\": true } } on a client entry.","commonSituations":"Copying a whole inbound block (which contains sniffing) into the per-user reverse object when wiring up reverse proxying.","solutions":["Remove \"sniffing\" from the reverse object","Configure sniffing at the inbound top level: \"sniffing\": { \"enabled\": true, \"destOverride\": [\"http\",\"tls\"] }"],"exampleFix":"// before\n\"reverse\": { \"tag\": \"bridge\", \"sniffing\": { \"enabled\": true } }\n// after\n\"reverse\": { \"tag\": \"bridge\" }  // sniffing belongs on the inbound, not here","handlingStrategy":"validation","validationCode":"if r := gjson.Get(clientRaw, \"reverse\"); r.Exists() {\n    if gjson.Get(r.Raw, \"sniffing\").Exists() {\n        return errors.New(\"reverse object must not contain \\\"sniffing\\\"; put sniffing on the inbound\")\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Sniffing is an inbound-level key, never a per-user one","Keep reverse objects to just { \"tag\": \"...\" }"],"tags":["config","vless","reverse-proxy","sniffing"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}