{"record":{"id":"834e2c9986f2c04f","repo":"XTLS/Xray-core","slug":"unknown-udp-mode","errorCode":null,"errorMessage":"unknown udp mode","messagePattern":"unknown udp mode","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/transport_finalmask.go","lineNumber":514,"sourceCode":"\t}\n\treturn &custom.ExprArg{\n\t\tValue: &custom.ExprArg_Expr{\n\t\t\tExpr: parsedExpr,\n\t\t},\n\t}, nil\n}\n\ntype HeaderCustomUDP struct {\n\tMode   string    `json:\"mode\"`\n\tClient []UDPItem `json:\"client\"`\n\tServer []UDPItem `json:\"server\"`\n}\n\nfunc (c *HeaderCustomUDP) Build() (proto.Message, error) {\n\tswitch c.Mode {\n\tcase \"\", \"prefix\", \"standalone\":\n\tdefault:\n\t\treturn nil, errors.New(\"unknown udp mode\")\n\t}\n\n\tfor _, item := range c.Client {\n\t\tif err := validateCustomItemSpec(item.Capture, item.Packet, item.Rand, item.Reuse, item.Transform); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tfor _, item := range c.Server {\n\t\tif err := validateCustomItemSpec(item.Capture, item.Packet, item.Rand, item.Reuse, item.Transform); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tclient := make([]*custom.UDPItem, 0, len(c.Client))\n\tfor _, item := range c.Client {\n\t\tif item.RandRange == nil {\n\t\t\titem.RandRange = &Int32Range{From: 0, To: 255}\n\t\t}","sourceCodeStart":496,"sourceCodeEnd":532,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/transport_finalmask.go#L496-L532","documentation":"HeaderCustomUDP.Build (infra/conf/transport_finalmask.go:514) validates the UDP mask's \"mode\" against an allow-list: \"\" (default), \"prefix\" (prepend custom data to each datagram), and \"standalone\" (send custom data as its own datagrams). Any other string returns \"unknown udp mode\".","triggerScenarios":"\"mode\":\"suffix\", \"mode\":\"PREFIX\" (case-sensitive switch — not lowered), \"mode\":\"prepend\". An omitted mode is valid (empty string).","commonSituations":"Guessing mode names instead of consulting the vocabulary; copying TCP header-custom settings where mode doesn't exist; version skew where a fork added modes Xray-core doesn't know.","solutions":["Set mode to \"prefix\" or \"standalone\", or omit it entirely","Match case exactly; the switch is case-sensitive","Re-check the udpmask settings docs for the header-custom type"],"exampleFix":"// before\n\"mode\": \"prepend\"\n// after\n\"mode\": \"prefix\"","handlingStrategy":"validation","validationCode":"const MODES = new Set(['', 'prefix', 'standalone']);\nif (!MODES.has(cfg.mode ?? '')) throw new Error(`unknown udp mode: ${cfg.mode} (use prefix/standalone or omit)`);","typeGuard":"const isUdpMode = (m: string) => ['', 'prefix', 'standalone'].includes(m);","tryCatchPattern":null,"preventionTips":["Remember the switch is case-sensitive","Omit mode when default behavior is fine"],"tags":["xray","go","transport","header-custom","udp","validation"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}