denoland/deno · error

Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an unsupported

Error message

Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an unsupported protocol: {}

What it means

OTEL_EXPORTER_OTLP_PROTOCOL picks the wire format for the OTLP exporter. Supported values are `console`, `http/protobuf` (also the default when the variable is unset or empty), `http/json` and `grpc`. Any other value aborts telemetry initialization.

Source

Thrown at ext/telemetry/lib.rs:1254

  // Parse the `OTEL_EXPORTER_OTLP_PROTOCOL` variable. The opentelemetry_*
  // crates don't do this automatically.
  // `opentelemetry_otlp::Protocol::Grpc` is feature-gated behind the
  // (tonic-based) `grpc-tonic` feature, which we don't enable because we ship
  // our own gRPC framing. Track the gRPC choice with a separate flag so the
  // `protocol` value is only ever the HTTP variant passed to the OTLP HTTP
  // exporter builder.
  let protocol_var = sys.env_var("OTEL_EXPORTER_OTLP_PROTOCOL");
  let (use_console_exporter, use_grpc, protocol) = match protocol_var.as_deref()
  {
    Ok("console") => (true, false, Protocol::HttpBinary),
    Ok("http/protobuf") | Ok("") | Err(std::env::VarError::NotPresent) => {
      (false, false, Protocol::HttpBinary)
    }
    Ok("http/json") => (false, false, Protocol::HttpJson),
    Ok("grpc") => (false, true, Protocol::HttpBinary),
    Ok(protocol) => {
      return Err(deno_core::anyhow::anyhow!(
        "Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an unsupported protocol: {}",
        protocol
      ));
    }
    Err(err) => {
      return Err(deno_core::anyhow::anyhow!(
        "Failed to read env var OTEL_EXPORTER_OTLP_PROTOCOL: {}",
        err
      ));
    }
  };

  // Define the resource attributes that will be attached to all log records.
  // These attributes are sourced as follows (in order of precedence):
  //   * The `service.name` attribute from the `OTEL_SERVICE_NAME` env var.
  //   * Additional attributes from the `OTEL_RESOURCE_ATTRIBUTES` env var.
  //   * Default attribute values defined here.
  // TODO(piscisaureus): add more default attributes (e.g. script path).

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Set the variable to one of `console`, `http/protobuf`, `http/json`, `grpc`
  2. Unset it to use the default `http/protobuf`
  3. Put the collector address in OTEL_EXPORTER_OTLP_ENDPOINT, never in the protocol variable

Example fix

# before — endpoint URL or bare format name
export OTEL_EXPORTER_OTLP_PROTOCOL=http://localhost:4317

# after — exact protocol name; endpoint goes in its own variable
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
Defensive patterns

Strategy: validation

Validate before calling

case "${OTEL_EXPORTER_OTLP_PROTOCOL:-}" in
  ""|console|http/protobuf|http/json|grpc) ;;
  *) echo "unsupported OTEL_EXPORTER_OTLP_PROTOCOL: '$OTEL_EXPORTER_OTLP_PROTOCOL'"; exit 1;;
esac
deno run --unstable-otel main.ts

Type guard

const PROTOCOLS = new Set(["console", "http/protobuf", "http/json", "grpc"]);
const isOtlpProtocol = (v: string): boolean => v === "" || PROTOCOLS.has(v);

Prevention

When it happens

Trigger: Setting the variable to an unsupported string: `protobuf`, `grpc/protobuf`, URL-escaped variants like `http%2Fprotobuf`, or a full URL such as `http://localhost:4317`.

Common situations: Confusing the protocol name with the endpoint URL; env values mangled by escaping when copied between systems; typos in Helm charts or docker-compose env blocks.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/7864c0c7cd1e7610. Report an issue: GitHub.