denoland/deno · error · anyhow::Error

Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an…

Error message

Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an unsupported protocol: {}

What it means

Deno's OTLP exporter setup reads OTEL_EXPORTER_OTLP_PROTOCOL to decide the transport. Exactly four non-empty strings are accepted: 'console' (print to stderr instead of exporting), 'http/protobuf' (default, also used when the var is empty or unset), 'http/json', and 'grpc'. Any other value fails telemetry init with this error.

Solutions

  1. Set the variable to one of: console, http/protobuf, http/json, grpc
  2. Unset it to get the default http/protobuf behavior
  3. Check for quoting artifacts: the value must be exactly the protocol string, no surrounding quotes or whitespace

Example fix

# before
export OTEL_EXPORTER_OTLP_PROTOCOL=HTTP/JSON  # -> unsupported protocol
deno run --otel app.ts

# after
export OTEL_EXPORTER_OTLP_PROTOCOL=http/json
deno run --otel app.ts
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED_PROTOCOLS = new Set(["", "console", "http/protobuf", "http/json", "grpc"]);
const proto = Deno.env.get("OTEL_EXPORTER_OTLP_PROTOCOL") ?? "";
if (!ALLOWED_PROTOCOLS.has(proto)) {
  throw new Error(`OTEL_EXPORTER_OTLP_PROTOCOL='${proto}' must be one of: ${[...ALLOWED_PROTOCOLS].join(", ")}`);
}

Try / catch

const { code, stderr } = await new Deno.Command("deno", { args: ["run", "--otel", "app.ts"] }).output();
if (code !== 0 && new TextDecoder().decode(stderr).includes("unsupported protocol")) {
  delete env.OTEL_EXPORTER_OTLP_PROTOCOL; // fall back to default http/protobuf
  // relaunch
}

Prevention

When it happens

Trigger: Running with --otel with OTEL_EXPORTER_OTLP_PROTOCOL set to values valid in other OTel SDKs but unsupported here, e.g. 'http/ndjson', 'HTTP/protobuf' (wrong case), 'grpc/protobuf', or a quoted value with stray characters like '"http/json"'.

Common situations: Reusing Docker/Kubernetes env blocks written for the Go or Java SDK; case mismatch (matching is exact); config-management tools wrapping values in quotes; copying from docs of a newer OTel spec revision.

Understand the failure class

Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.

Related errors


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

Appendix: 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 9ad36f7a2c)