Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for OpenTelemetry By James Joyner IV · · 9 min read

OpenTelemetry Error Guide: 'unable to parse OTTL statement' — Fix Transform Processor Syntax

Quick answer

Fix 'transform: unable to parse OTTL statement "set(attributes["env"], )": statement has invalid syntax' in the transform processor.

  • #opentelemetry
  • #observability
  • #troubleshooting
  • #errors
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

This error appears at Collector startup when the transform processor cannot compile one of its OTTL (OpenTelemetry Transformation Language) statements. Since OTTL is parsed before the pipeline starts, a syntax error stops the Collector from booting rather than dropping data at runtime:

transform: unable to parse OTTL statement "set(attributes["env"], )": statement has invalid syntax

A different mistake — a path that doesn’t exist in the chosen context — reads:

transform: unable to parse OTTL statement "set(resource.attributes["k8s.pod.name"], span.name)": segment "span" from path "span.name" is not a valid path in the metric context

unable to parse OTTL statement means the statement is malformed: a missing argument, an unbalanced bracket, a wrong path, or a function used in the wrong signal context. The Collector fails fast so a broken transform never silently mangles telemetry.

Symptoms

  • The Collector refuses to start; otelcol-contrib validate fails with unable to parse OTTL statement.
  • The log names the exact statement string and often the reason (invalid syntax, not a valid path).
  • The failure began right after editing a transform processor block.
  • A statement references a path (e.g. span.name) that doesn’t exist in that pipeline’s context (metric, datapoint, log).
  • A function call is missing an argument or has a trailing comma / unbalanced quote.

Common Root Causes

  • Missing argument — a function like set(target, value) is called with the value omitted, e.g. set(attributes["env"], ).
  • Wrong context path — using span.* inside a metric_statements block, or resource where only attributes is valid for that context.
  • Unbalanced brackets or quotes — a stray [, ), or unescaped " breaks the parser.
  • Wrong statement group — placing a trace-oriented statement under metric_statements: (or vice versa) so the path is invalid.
  • Unknown function or converter — a typo like Set(...) (OTTL editors are lowercase) or a converter name that doesn’t exist in your Collector version.
  • Bad conditional — a malformed where clause or comparison operator the OTTL grammar doesn’t accept.

Diagnostic Workflow

OTTL errors are caught before startup, so validate the config offline first — it prints the exact failing statement:

otelcol-contrib validate --config /etc/otelcol-contrib/config.yaml
journalctl -u otelcol-contrib --since '5 min ago' | grep -i 'unable to parse OTTL\|invalid syntax\|not a valid path'

Locate the broken statement. The example error omits the value in set(...). A correct transform processor supplies both the target path and a value, and puts statements under the matching signal group:

processors:
  transform:
    error_mode: propagate        # fail fast on bad data; or 'ignore' to skip
    trace_statements:
      - context: span
        statements:
          - set(attributes["env"], "prod")
          - set(attributes["deployment.region"], resource.attributes["cloud.region"])
          - delete_key(attributes, "http.request.header.authorization")
    metric_statements:
      - context: datapoint
        statements:
          - set(attributes["env"], "prod")
    log_statements:
      - context: log
        statements:
          - set(attributes["env"], "prod")

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, transform, batch]
      exporters: [otlp]

Key rules that fix most parse errors:

  • Every function argument must be present — set(target, value) needs both operands.
  • Use the right context path: inside context: span use attributes[...] and resource.attributes[...]; inside context: metric/datapoint you cannot reference span.*.
  • Statement editors and functions are lowercase (set, delete_key, keep_keys, replace_pattern).
  • Match the statement group to the signal: trace_statements, metric_statements, log_statements.

Re-validate after each edit until the config compiles cleanly:

otelcol-contrib validate --config /etc/otelcol-contrib/config.yaml && echo OK

Example Root Cause Analysis

An engineer wanted to stamp an env attribute onto every span and started from a snippet, intending to fill in the value later: set(attributes["env"], ). They committed it, and the Collector Deployment went into CrashLoopBackOff because startup aborted with transform: unable to parse OTTL statement "set(attributes["env"], )": statement has invalid syntax. Nothing exported at all — the whole Collector was down, not just the transform.

The fix had two parts. First, the statement was completed with a real value, set(attributes["env"], "prod"), and the value was later sourced dynamically from resource.attributes["deployment.environment"] where present. Second, otelcol-contrib validate was wired into the CI pipeline and a pre-deploy init check so a malformed OTTL statement fails the build instead of crash-looping production. After the fix the Collector started cleanly and every span carried the env attribute.

Prevention Best Practices

  • Run otelcol-contrib validate in CI and as a startup gate so OTTL syntax errors never reach a running Collector.
  • Never commit half-written statements; set(target, value) always needs both operands filled in.
  • Match statements to their signal group and context — don’t reference span.* paths inside metric or log statements.
  • Keep functions and paths lowercase and check converter names against your exact Collector version’s OTTL docs.
  • Set error_mode deliberately: propagate to fail fast on bad data, or ignore to skip individual failing records at runtime (this does not excuse a parse error, which still blocks startup).
  • Build transforms incrementally, validating after each statement, rather than pasting a large block and debugging all at once.

Quick Command Reference

# Validate config offline — prints the exact failing OTTL statement
otelcol-contrib validate --config /etc/otelcol-contrib/config.yaml

# Find OTTL parse failures in the Collector logs
journalctl -u otelcol-contrib -f | grep -i 'unable to parse OTTL\|invalid syntax'

# Confirm the Collector actually started after fixing the statement
journalctl -u otelcol-contrib --since '2 min ago' | grep -i 'Everything is ready'

# In Kubernetes, catch a crash-loop from a bad transform
kubectl get pods -l app=otel-collector

Conclusion

unable to parse OTTL statement is a compile-time error: the transform processor found a statement it cannot understand — a missing argument, an unbalanced bracket, or a path that doesn’t exist in the chosen context — and refused to start rather than corrupt your telemetry. Fix the statement (both operands present, correct context path, right signal group, lowercase functions), then re-run otelcol-contrib validate. Wiring that validation into CI and a startup gate turns a production crash-loop into a caught build failure.

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.