XTLS/Xray-core · error

transform arg must set exactly one value

Error message

transform arg must set exactly one value

What it means

buildCustomTransformArg (infra/conf/transport_finalmask.go:454) counts the value fields set on a transform argument — str, bytes, u64, reuse, metadata, transform — and requires exactly one. Zero set, or two or more set, returns "transform arg must set exactly one value"; an arg is a tagged union, not a record.

Source

Thrown at infra/conf/transport_finalmask.go:454

func buildCustomTransformArg(arg CustomTransformArg) (*custom.ExprArg, error) {
	kindCount := 0
	if len(arg.Bytes) > 0 {
		kindCount++
	}
	if arg.U64 != nil {
		kindCount++
	}
	if arg.Reuse != "" {
		kindCount++
	}
	if arg.Metadata != "" {
		kindCount++
	}
	if arg.Transform != nil {
		kindCount++
	}
	if kindCount != 1 {
		return nil, errors.New("transform arg must set exactly one value")
	}

	if len(arg.Bytes) > 0 {
		value, err := PraseByteSlice(arg.Bytes, arg.Type)
		if err != nil {
			return nil, err
		}
		return &custom.ExprArg{
			Value: &custom.ExprArg_Bytes{
				Bytes: value,
			},
		}, nil
	}
	if arg.U64 != nil {
		return &custom.ExprArg{
			Value: &custom.ExprArg_U64{
				U64: *arg.U64,
			},

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Set exactly one value field per arg object
  2. Chain multiple values as multiple args consumed by the op instead of one arg with several fields
  3. Remove default/placeholder entries like "u64":0 — even an explicit zero counts as set

Example fix

// before
"args": [ { "str": "id-", "u64": 0 } ]
// after
"args": [ { "str": "id-" }, { "u64": 7 } ]
Defensive patterns

Strategy: validation

Validate before calling

const ARG_FIELDS = ['str','bytes','u64','reuse','metadata','transform'];
for (const a of t.args ?? []) {
  const set = ARG_FIELDS.filter(k => a[k] !== undefined && a[k] !== null);
  if (set.length !== 1) throw new Error(`arg must set exactly one of ${ARG_FIELDS}, set: ${set}`);
}

Type guard

const isSingleValueArg = (a:any) => ARG_FIELDS.filter(k => a[k] !== undefined && a[k] !== null).length === 1;

Prevention

When it happens

Trigger: {} as an arg; {"str":"a","reuse":"b"}; {"bytes":"...","u64":1}. Note bytes+type is fine because type is a decoder hint, not a value; but any two value fields together fail.

Common situations: Copy-pasting arg templates and leaving placeholder values; adding a fallback value 'just in case'; treating args as a struct where you fill several fields.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/33c86b81f54fad02. Report an issue: GitHub.