mikefarah/yq · error

must use variable with a pipe, e.g. `exp as $x | ...`

Error message

must use variable with a pipe, e.g. `exp as $x | ...`

What it means

The `as` variable-binding operator only makes sense inside a pipeline (`exp as $x | ...`). yq parses variables so that, when used outside a pipe context, the placeholder handler `useWithPipe` runs and returns this error instead of silently doing nothing.

Source

Thrown at pkg/yqlib/operator_variables.go:23

	"fmt"
)

func getVariableOperator(_ *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
	variableName := expressionNode.Operation.StringValue
	log.Debugf("getVariableOperator %v", variableName)
	result := context.GetVariable(variableName)
	if result == nil {
		result = list.New()
	}
	return context.ChildContext(result), nil
}

type assignVarPreferences struct {
	IsReference bool
}

func useWithPipe(_ *dataTreeNavigator, _ Context, _ *ExpressionNode) (Context, error) {
	return Context{}, fmt.Errorf("must use variable with a pipe, e.g. `exp as $x | ...`")
}

// variables are like loops in jq
// https://stedolan.github.io/jq/manual/#Variable
func variableLoop(d *dataTreeNavigator, context Context, originalExp *ExpressionNode) (Context, error) {
	log.Debug("variable loop!")
	results := list.New()
	var evaluateAllTogether = true
	for matchEl := context.MatchingNodes.Front(); matchEl != nil; matchEl = matchEl.Next() {
		evaluateAllTogether = evaluateAllTogether && matchEl.Value.(*CandidateNode).EvaluateTogether
		if !evaluateAllTogether {
			break
		}
	}
	if evaluateAllTogether {
		return variableLoopSingleChild(d, context, originalExp)
	}

View on GitHub (pinned to 8b5af0694b)

Solutions

  1. Add the pipe and continuation, e.g. `.a as $x | .b + $x`
  2. If you only wanted to reference a value, drop the `as` syntax and pipe the expression directly
  3. Check the expression string for truncation — the `| ...` half may have been lost when quoting in the shell
  4. Consult the variables docs: bindings are per-expression, not persistent across yq runs

Example fix

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

Strategy: try-catch

Validate before calling

// Validate expression has a pipe continuation after 'as'
if strings.Contains(expr, " as $") && !strings.Contains(expr, "|") {
	return fmt.Errorf("'as' requires a pipe continuation: exp as $x | ...")
}

Try / catch

out, err := yqEval(expr, doc)
if err != nil && strings.Contains(err.Error(), "must use variable with a pipe") {
	// fix expression: append '| ...' continuation
}

Prevention

When it happens

Trigger: Using a variable operator form that is not attached to a pipe, e.g. `yq '$x'` with no binding, or an expression where `as` isn't followed by `|`, causing the lexer to dispatch to useWithPipe.

Common situations: Copy-pasting jq snippets without the trailing pipe, forgetting the `| ...` continuation after `as $x`, or writing `yq 'exp as $x'` and expecting the binding to persist to a later invocation.

Related errors


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