mikefarah/yq · error

unsupported character %q in raw HCL expression

Error message

unsupported character %q in raw HCL expression

What it means

When encoding an attribute whose value is a raw HCL expression, yq tokenizes the string character-by-character and only supports a fixed set of operators/characters. Any other character in a raw expression string raises this error.

Source

Thrown at pkg/yqlib/encoder_hcl.go:349

			continue
		case ch == '(':
			tokens = append(tokens, &hclwrite.Token{Type: hclsyntax.TokenOParen, Bytes: []byte{'('}})
		case ch == ')':
			tokens = append(tokens, &hclwrite.Token{Type: hclsyntax.TokenCParen, Bytes: []byte{')'}})
		case ch == ',':
			tokens = append(tokens, &hclwrite.Token{Type: hclsyntax.TokenComma, Bytes: []byte{','}})
		case ch == '.':
			tokens = append(tokens, &hclwrite.Token{Type: hclsyntax.TokenDot, Bytes: []byte{'.'}})
		case ch == '+':
			tokens = append(tokens, &hclwrite.Token{Type: hclsyntax.TokenPlus, Bytes: []byte{'+'}})
		case ch == '-':
			tokens = append(tokens, &hclwrite.Token{Type: hclsyntax.TokenMinus, Bytes: []byte{'-'}})
		case ch == '*':
			tokens = append(tokens, &hclwrite.Token{Type: hclsyntax.TokenStar, Bytes: []byte{'*'}})
		case ch == '/':
			tokens = append(tokens, &hclwrite.Token{Type: hclsyntax.TokenSlash, Bytes: []byte{'/'}})
		default:
			return nil, fmt.Errorf("unsupported character %q in raw HCL expression", ch)
		}
		i++
	}
	return tokens, nil
}

// encodeAttribute encodes a value as an HCL attribute
func (he *hclEncoder) encodeAttribute(body *hclwrite.Body, key string, valueNode *CandidateNode) error {
	if valueNode.Kind == ScalarNode && valueNode.Tag == "!!str" {
		// Handle unquoted expressions (as-is, without quotes)
		if valueNode.Style == 0 {
			tokens, err := tokensForRawHCLExpr(valueNode.Value)
			if err != nil {
				return err
			}
			body.SetAttributeRaw(key, tokens)
			return nil
		}

View on GitHub (pinned to 8b5af0694b)

Solutions

  1. Restrict raw expressions to the supported token set (identifiers, numbers, dots, + - * /)
  2. Replace unsupported constructs with supported HCL equivalents before encoding
  3. Drop the raw-expression styling so the value is encoded as a normal string literal
  4. Extend tokensForRawHCLExpr if you maintain a fork and need more characters

Example fix

// before (value flagged as raw expr): "${var.x}"
// after: use "var.x" as the raw expression, or remove raw styling to emit a quoted string
Defensive patterns

Strategy: validation

Validate before calling

// allow-list check before marking a value as raw HCL:
var rawExprAllowed = regexp.MustCompile(`^[A-Za-z0-9_.+\-*/ ]+$`)
func safeRawExpr(s string) bool { return rawExprAllowed.MatchString(s) }

Type guard

func isSupportedRawExpr(s string) bool {
  for _, ch := range s {
    switch { case ch >= 'a' && ch <= 'z', ch >= 'A' && ch <= 'Z',
      ch >= '0' && ch <= '9',
      strings.ContainsRune("._+-*/ ", ch):
    default: return false }
  }
  return len(s) > 0
}

Try / catch

toks, err := tokensForRawHCLExpr(expr)
if err != nil {
    // fall back: encode as a quoted string literal instead of a raw expression
    return writeStringLiteral(body, key, expr)
}

Prevention

When it happens

Trigger: Encoding a mapping value marked as raw HCL (e.g. values styled/raw strings like `${var.x}` or function calls `foo(bar)`) where the string contains characters outside the supported token set (identifiers, digits, dots, +, -, *, /, etc.), such as parentheses, braces, or comparison operators.

Common situations: Terraform users storing `${...}` interpolations or `lookup(a, "b")` style expressions in YAML and expecting `to hcl` to emit them verbatim; template characters like `%` or `?` in raw strings.

Related errors


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