mikefarah/yq · error

RHS of 'as' operator must be a variable name e.g. $foo

Error message

RHS of 'as' operator must be a variable name e.g. $foo

What it means

variableLoopSingleChild inspects the RHS of the 'as' expression (e.g. '. as $foo') and its guard found the right-hand side is not a variable binding — the parse produced something other than a $name token. This is a syntax-shape check: 'as' must be followed immediately by a variable name for the loop to bind each result.

Source

Thrown at pkg/yqlib/operator_variables.go:60

	for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
		result, err := variableLoopSingleChild(d, context.SingleChildContext(el.Value.(*CandidateNode)), originalExp)
		if err != nil {
			return Context{}, err
		}
		results.PushBackList(result.MatchingNodes)
	}
	return context.ChildContext(results), nil
}

func variableLoopSingleChild(d *dataTreeNavigator, context Context, originalExp *ExpressionNode) (Context, error) {

	variableExp := originalExp.LHS
	lhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), variableExp.LHS)
	if err != nil {
		return Context{}, err
	}
	if variableExp.RHS.Operation.OperationType.Type != "GET_VARIABLE" {
		return Context{}, fmt.Errorf("RHS of 'as' operator must be a variable name e.g. $foo")
	}
	variableName := variableExp.RHS.Operation.StringValue

	prefs := variableExp.Operation.Preferences.(assignVarPreferences)

	results := list.New()

	// now we loop over lhs, set variable to each result and calculate originalExp.Rhs
	for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() {
		log.Debugf("PROCESSING VARIABLE: %v", NodeToString(el.Value.(*CandidateNode)))
		var variableValue = list.New()
		if prefs.IsReference {
			variableValue.PushBack(el.Value)
		} else {
			candidateCopy := el.Value.(*CandidateNode).Copy()
			variableValue.PushBack(candidateCopy)
		}
		newContext := context.ChildContext(context.MatchingNodes)

View on GitHub (pinned to 8b5af0694b)

Solutions

  1. Use a bare dollar variable as RHS: `.a as $x | ...`
  2. If using double quotes in bash, escape the variable (`\$x`) or switch to single quotes so yq receives the literal `$x`
  3. Compute derived values after the binding, e.g. `.a as $x | $x + 1`, not `as ($x + 1)`
  4. Check lexer parsing: ensure the variable token wasn't split by spaces or special characters

Example fix

// before
yq '.a as x | .b + x' file.yaml
// after
yq '.a as $x | .b + $x' file.yaml
Defensive patterns

Strategy: validation

Validate before calling

// Ensure RHS of 'as' is a bare $variable
re := regexp.MustCompile(`\bas\s+\$\w+\s*\|`)
if strings.Contains(expr, " as ") && !re.MatchString(expr) {
	return fmt.Errorf("RHS of 'as' must be a $variable")
}

Type guard

func isVarRef(tok string) bool { return regexp.MustCompile(`^\$\w+$`).MatchString(tok) }

Try / catch

out, err := yqEval(expr, doc)
if err != nil && strings.Contains(err.Error(), "must be a variable name") {
	// rewrite binding as plain $var then compute after pipe
}

Prevention

When it happens

Trigger: Writing `yq '.a as x | ...'` (missing `$`), `.a as ($x + 1) | ...`, or otherwise placing a computed expression where only a variable name is allowed.

Common situations: Typos omitting the `$` prefix, copying jq patterns where yq's grammar is stricter, or shell interpolation accidentally mangling the `$x` (single vs double quoting in bash eats `$x`).

Related errors


AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05). Data as JSON: /api/errors/3ad928aa6ec472a8. Report an issue: GitHub.