mikefarah/yq · error

cannot encode %v as URI, can only operate on strings. Please

Error message

cannot encode %v as URI, can only operate on strings. Please first pipe through another encoding operator to convert the value to a string

What it means

The sh (shell quoting) encoder can only serialize string nodes. It checks `node.guessTagFromCustomType() != "!!str"` and rejects anything else (ints, bools, maps, seqs) telling you to convert the value to a string first. The message mentions URI because the sh encoder is shared with the URI output path.

Source

Thrown at pkg/yqlib/encoder_sh.go:36

func NewShEncoder() Encoder {
	return &shEncoder{false}
}

func (e *shEncoder) CanHandleAliases() bool {
	return false
}

func (e *shEncoder) PrintDocumentSeparator(_ io.Writer) error {
	return nil
}

func (e *shEncoder) PrintLeadingContent(_ io.Writer, _ string) error {
	return nil
}

func (e *shEncoder) Encode(writer io.Writer, node *CandidateNode) error {
	if node.guessTagFromCustomType() != "!!str" {
		return fmt.Errorf("cannot encode %v as URI, can only operate on strings. Please first pipe through another encoding operator to convert the value to a string", node.Tag)
	}

	return writeString(writer, e.encode(node.Value))
}

// put any (shell-unsafe) characters into a single-quoted block, close the block lazily
func (e *shEncoder) encode(input string) string {
	const quote = '\''
	var inQuoteBlock = false
	var encoded strings.Builder
	encoded.Grow(len(input))

	for _, ir := range input {
		// open or close a single-quote block
		if ir == quote {
			if inQuoteBlock {
				// get out of a quote block for an input quote
				encoded.WriteRune(quote)

View on GitHub (pinned to 8b5af0694b)

Solutions

  1. Force string conversion: `yq -o sh '.count | tostring' file.yaml`.
  2. Or retag: `yq -o sh '.count tag="!!str"' file.yaml`.
  3. For multiple values, map over them: `yq -o sh '.[] | tostring'`.
  4. Quote in the YAML source (`count: "123"`) if the value is inherently textual.

Example fix

# before
yq -o sh '.port' config.yaml      # port: 8080 (!!int) -> error

# after
yq -o sh '.port | tostring' config.yaml
Defensive patterns

Strategy: type-guard

Validate before calling

[ "$(yq '.port | tag' config.yaml)" = "!!str" ] || echo "pipe through tostring"

Type guard

isStringNode() { [ "$(yq "$1" | yq 'tag')" = "!!str" ]; }

Try / catch

val=$(yq -o sh '.port | tostring' config.yaml) || val=$(yq -o sh '.port' config.yaml)

Prevention

When it happens

Trigger: `yq -o sh '.count' file.yaml` where `.count` is `!!int`; piping a boolean/null node to `-o sh`; encoding a map/sequence node with `-o sh`/`@uri`.

Common situations: Exporting numeric env vars for `eval` in shell scripts; quoting timestamps or booleans for shell; forgetting YAML auto-typing turns `true`, `123`, `null` into non-string tags.

Related errors


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