mikefarah/yq · error

system operator: command must be a non-empty string

Error message

system operator: command must be a non-empty string

What it means

The `system` operator rejects an empty-string command. After confirming the command node is a string scalar, resolveCommandNode checks that it is non-empty; an empty string cannot name a program to execute and is treated as an error rather than a no-op.

Source

Thrown at pkg/yqlib/operator_system.go:56

	if argsNode.Kind != ScalarNode {
		return nil, fmt.Errorf("system operator: args must be a non-null scalar or sequence of non-null scalars; got kind=%v tag=%v", argsNode.Kind, argsNode.Tag)
	}
	return []string{argsNode.Value}, nil
}

func resolveCommandNode(commandNodes Context) (string, error) {
	if commandNodes.MatchingNodes.Front() == nil {
		return "", fmt.Errorf("system operator: command expression returned no results")
	}
	if commandNodes.MatchingNodes.Len() > 1 {
		log.Debugf("system operator: command expression returned %d results, using first", commandNodes.MatchingNodes.Len())
	}
	cmdNode := commandNodes.MatchingNodes.Front().Value.(*CandidateNode)
	if cmdNode.Kind != ScalarNode || cmdNode.guessTagFromCustomType() != "!!str" {
		return "", fmt.Errorf("system operator: command must be a string scalar")
	}
	if cmdNode.Value == "" {
		return "", fmt.Errorf("system operator: command must be a non-empty string")
	}
	return cmdNode.Value, nil
}

func systemOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
	if !ConfiguredSecurityPreferences.EnableSystemOps {
		return Context{}, fmt.Errorf("system operations are disabled, use --security-enable-system-operator to enable")
	}

	// determine at parse time whether we have (command; args) or just (command)
	hasArgs := expressionNode.RHS.Operation.OperationType == blockOpType

	var results = list.New()

	for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
		candidate := el.Value.(*CandidateNode)
		nodeContext := context.SingleReadonlyChildContext(candidate)

View on GitHub (pinned to 8b5af0694b)

Solutions

  1. Supply a default command: `system(.cmd // "echo")` so empty resolves to a valid command
  2. Guard before running: only evaluate system when the command is non-empty, e.g. wrap in an if: `select(.cmd != "") | system(.cmd)`
  3. Fix the input document so the command field contains the actual program name

Example fix

// before: .cmd is "" in the document
system(.cmd)
// after: guard against empty
select(.cmd != "" and .cmd != null) | system(.cmd)
Defensive patterns

Strategy: validation

Validate before calling

// skip empty commands
select(.cmd != null and .cmd != "") | system(.cmd)

Prevention

When it happens

Trigger: The command field exists in the YAML but is empty, e.g. `cmd: ""` or `cmd:` with no value resolved to an empty scalar, then `system(.cmd)` is evaluated.

Common situations: Unset config values in CI pipelines (empty env-derived placeholders), template-rendered files where the command was substituted with an empty string, or optional fields defaulted to "".

Related errors


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