denoland/deno · error

Failed to read env var OTEL_EXPORTER_OTLP_PROTOCOL: {}

Error message

Failed to read env var OTEL_EXPORTER_OTLP_PROTOCOL: {}

What it means

Startup reads OTEL_EXPORTER_OTLP_PROTOCOL through std::env::var; only VarError::NotPresent is treated as unset (defaulting to http/protobuf). Any other VarError — in practice NotUnicode, a value with invalid UTF-8 bytes — produces this message together with the underlying error text.

Source

Thrown at ext/telemetry/lib.rs:1260

  // `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).
  // The base resource picks up `service.name`, the `telemetry.sdk.*`
  // attributes and any `OTEL_RESOURCE_ATTRIBUTES`/`OTEL_SERVICE_NAME` values.
  let base_resource = Resource::builder().build();
  let sdk_language = base_resource
    .get(&Key::new(TELEMETRY_SDK_LANGUAGE))
    .unwrap();

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Re-export the variable with a clean ASCII/UTF-8 value: `export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf`
  2. Find and fix the writer that produced the non-UTF-8 value (CI secret definitions, Dockerfile ENV lines, .env encodings)
  3. As a stopgap, unset the variable to fall back to the default http/protobuf protocol

Example fix

# before — value inherited with non-UTF-8 bytes, startup fails
deno run --unstable-otel main.ts

# after — normalize to clean ASCII before starting
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
deno run --unstable-otel main.ts
Defensive patterns

Strategy: validation

Validate before calling

# normalize instead of trusting inherited environments
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
deno run --unstable-otel main.ts

Prevention

When it happens

Trigger: The process environment contains OTEL_EXPORTER_OTLP_PROTOCOL with non-UTF-8 bytes: written by a buggy script, a mis-encoded CI secret, or an exec call passing raw byte environments.

Common situations: CI secret stores that saved the value with a BOM or binary encoding; container images built with broken locale handling; wrapper processes forwarding env bytes unvalidated.

Related errors


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