{"record":{"id":"de3cb495b24751db","repo":"XTLS/Xray-core","slug":"invalid-variable-name","errorCode":null,"errorMessage":"invalid variable name","messagePattern":"invalid variable name","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/transport_finalmask.go","lineNumber":374,"sourceCode":"\tOp   string               `json:\"op\"`\n\tArgs []CustomTransformArg `json:\"args\"`\n}\n\ntype CustomTransformArg struct {\n\tType      string           `json:\"type\"`\n\tBytes     json.RawMessage  `json:\"bytes\"`\n\tU64       *uint64          `json:\"u64\"`\n\tReuse     string           `json:\"reuse\"`\n\tMetadata  string           `json:\"metadata\"`\n\tTransform *CustomTransform `json:\"transform\"`\n}\n\nfunc validateCustomVarName(name string) error {\n\tif name == \"\" {\n\t\treturn nil\n\t}\n\tif !customVarNamePattern.MatchString(name) {\n\t\treturn errors.New(\"invalid variable name\")\n\t}\n\treturn nil\n}\n\nfunc validateCustomItemSpec(capture string, packet json.RawMessage, rand int32, reuse string, transform *CustomTransform) error {\n\tif err := validateCustomVarName(capture); err != nil {\n\t\treturn err\n\t}\n\tif err := validateCustomVarName(reuse); err != nil {\n\t\treturn err\n\t}\n\n\tkindCount := 0\n\tif len(packet) > 0 {\n\t\tkindCount++\n\t}\n\tif rand > 0 {\n\t\tkindCount++","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/transport_finalmask.go#L356-L392","documentation":"validateCustomVarName (infra/conf/transport_finalmask.go:374) checks every \"capture\" and \"reuse\" variable name in header-custom TCP/UDP masks against ^[A-Za-z_][A-Za-z0-9_]*$. Empty is allowed (no-op); anything else — spaces, dashes, digits first, non-ASCII, $ prefixes — returns \"invalid variable name\".","triggerScenarios":"An item with \"capture\":\"pkt 1\", \"reuse\":\"$var\", \"capture\":\"1st\", or names using '-' instead of '_'. Runs during validateCustomItemSpec for every clients/servers/errors (TCP) and client/server (UDP) item.","commonSituations":"Users writing shell-style ($VAR) or template-style ({var}) names; regex-derived names with special characters; translating examples from another language's identifier rules.","solutions":["Use plain C-style identifiers: letter or underscore first, then letters/digits/underscores","Drop sigils: \"$payload\" -> \"payload\"; \"first-packet\" -> \"first_packet\"","Leave capture/reuse empty when the item neither saves nor loads a variable"],"exampleFix":"// before\n{ \"capture\": \"$hello\", \"packet\": [72,105] }\n// after\n{ \"capture\": \"hello\", \"packet\": [72,105] }","handlingStrategy":"type-guard","validationCode":"const IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;\nfor (const it of items) {\n  if (it.capture && !IDENT.test(it.capture)) throw new Error(`bad capture name: ${it.capture}`);\n  if (it.reuse && !IDENT.test(it.reuse)) throw new Error(`bad reuse name: ${it.reuse}`);\n}","typeGuard":"const isVarName = (s: string) => s === '' || /^[A-Za-z_][A-Za-z0-9_]*$/.test(s);","tryCatchPattern":null,"preventionTips":["Use plain C-style identifiers for capture/reuse","Ban $, {}, -, and spaces in variable names at the generator level"],"tags":["xray","go","transport","header-custom","validation","naming"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}