XTLS/Xray-core · error
transform op is required
Error message
transform op is required
What it means
buildCustomTransform (infra/conf/transport_finalmask.go:415) requires every transform object to name its operation: "transform":{"op":""} (or op omitted) fails with "transform op is required". The op string selects the expression/function applied to transform args when building the custom.Expr.
Source
Thrown at infra/conf/transport_finalmask.go:415
if transform != nil {
kindCount++
}
if kindCount > 1 {
return errors.New("exactly one item kind must be set")
}
if kindCount == 0 && capture != "" {
return errors.New("exactly one item kind must be set")
}
return nil
}
func buildCustomTransform(transform *CustomTransform) (*custom.Expr, error) {
if transform == nil {
return nil, nil
}
if transform.Op == "" {
return nil, errors.New("transform op is required")
}
if len(transform.Args) == 0 {
return nil, errors.New("transform args are required")
}
args := make([]*custom.ExprArg, 0, len(transform.Args))
for _, arg := range transform.Args {
parsedArg, err := buildCustomTransformArg(arg)
if err != nil {
return nil, err
}
args = append(args, parsedArg)
}
return &custom.Expr{
Op: transform.Op,
Args: args,
}, nilView on GitHub (pinned to 7d214f8b09)
Solutions
- Set "op" to a supported operation name in every transform object, including nested ones
- Check the project's transform op vocabulary (see usages of custom.Expr / docs) before inventing names
- If no operation is needed, remove the transform entirely
Example fix
// before
"transform": { "args": [ { "reuse": "v" } ] }
// after
"transform": { "op": "concat", "args": [ { "reuse": "v" } ] } Defensive patterns
Strategy: validation
Validate before calling
function checkTransform(t:any){
if (!t) return;
if (!t.op) throw new Error('transform.op required');
if (!Array.isArray(t.args) || t.args.length === 0) throw new Error('transform.args required');
for (const a of t.args) if (a.transform) checkTransform(a.transform);
}
for (const it of items) checkTransform(it.transform); Type guard
const isTransform = (t:any) => t == null || (typeof t.op === 'string' && t.op !== '' && Array.isArray(t.args) && t.args.length > 0);
Prevention
- Recursively validate transforms including nested arg transforms
- Template every transform as {op, args} from the start
When it happens
Trigger: Any item with "transform":{"args":[...]} but no "op", or op:"" . Also triggered inside nested transform args (buildCustomTransformArg recurses into arg.Transform) with the same defect.
Common situations: Writing a transform to wrap a variable and forgetting the operation name; trimming an example transform down to args only; nested transforms where the inner object lacks op.
Related errors
- transform args are required
- transform arg must set exactly one value
- invalid randRange
- invalid variable name
- exactly one item kind must be set
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/cb0fc493e96c0aa8.
Report an issue: GitHub.