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
- Use a bare dollar variable as RHS: `.a as $x | ...`
- If using double quotes in bash, escape the variable (`\$x`) or switch to single quotes so yq receives the literal `$x`
- Compute derived values after the binding, e.g. `.a as $x | $x + 1`, not `as ($x + 1)`
- 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
- Use single quotes around expressions in bash so $x is not expanded
- Only place plain $variables after `as`; compute derived values after the pipe
- Grep CI configs for `as ` expressions lacking $ variables
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
- must use variable with a pipe, e.g. `exp as $x | ...`
- with must be given a block (;), got %v instead
- yaml node has no content
- orderedMap: invalid yaml node
- INI encoder supports only MappingNode at the root level, got
AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05).
Data as JSON: /api/errors/3ad928aa6ec472a8.
Report an issue: GitHub.