mikefarah/yq · error

unknown operator %v

Error message

unknown operator %v

What it means

GetMatchingNodes dispatches an expression node to its registered operator handler (OperationType.Handler). If the handler is nil — the OperationType was never fully registered, or an Operation was constructed with an unknown/custom operation type — yq cannot evaluate it and returns 'unknown operator %v' naming the operation type. This means the expression referenced an operator yq does not know how to execute.

Source

Thrown at pkg/yqlib/data_tree_navigator.go:66

	return err
}

func (d *dataTreeNavigator) GetMatchingNodes(context Context, expressionNode *ExpressionNode) (Context, error) {
	if expressionNode == nil {
		log.Debugf("getMatchingNodes - nothing to do")
		return context, nil
	}
	log.Debugf("Processing Op: %v", expressionNode.Operation.toString())
	if log.IsEnabledFor(slog.LevelDebug) {
		for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
			log.Debug(NodeToString(el.Value.(*CandidateNode)))
		}
	}
	handler := expressionNode.Operation.OperationType.Handler
	if handler != nil {
		return handler(d, context, expressionNode)
	}
	return Context{}, fmt.Errorf("unknown operator %v", expressionNode.Operation.OperationType.Type)

}

View on GitHub (pinned to 8b5af0694b)

Solutions

  1. If calling the Go API, only create Operations from the exported OpType variables (e.g. yqlib.CreateStringOpType-style registrations) rather than hand-built operationType structs.
  2. Verify the operator name/expression syntax against your yq version's docs (`yq --help` or operator docs); upgrade yq if the operator was added in a newer release.
  3. If maintaining a fork, ensure every operationType in operation.go sets Handler and that lexer_participle.go does not reference a nil-handler type.
  4. Reproduce with a stock yq binary: if the same expression works there, the issue is in your custom build/integration.

Example fix

// before: hand-rolled operation with no handler
op := &yqlib.Operation{OperationType: &yqlib.OperationType{Type: "FROBNICATE"}}
// → unknown operator FROBNICATE
// after: use a registered op type
op := yqlib.Operation{OperationType: yqlib.StringOpType} // or parse via NewExpressionParser
Defensive patterns

Strategy: validation

Validate before calling

// Go: build operations only from registered OpTypes
func isRegisteredOp(opType *yqlib.OperationType) bool {
    return opType != nil && opType.Handler != nil
}

Type guard

if exprNode != nil && exprNode.Operation != nil &&
    (exprNode.Operation.OperationType == nil || exprNode.Operation.OperationType.Handler == nil) {
    return fmt.Errorf("operator %q has no handler", exprNode.Operation.OperationType.Type)
}

Try / catch

// Go
out, err := navigator.GetMatchingNodes(ctx, exprNode)
if err != nil {
    if strings.HasPrefix(err.Error(), "unknown operator ") {
        return fmt.Errorf("expression uses unsupported operator; upgrade yq or fix expression: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Evaluating an expression whose Operation.OperationType has no Handler, e.g. constructing Operation structs programmatically via the yqlib API with a made-up operationType, or a lexer/operation.go registration mismatch (custom builds where an operator's Handler was left nil).

Common situations: Embedding yqlib in Go and building ExpressionNodes by hand instead of through the parser; custom forks or trimmed builds where an operator was registered in the lexer but its Handler is nil; version skew where an expression string uses an operator that does not exist in the installed yq version (usually caught earlier by the lexer, but API users can hit it here).

Related errors


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