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
- Set the variable to one of: console, http/protobuf, http/json, grpc
- Unset it to get the default http/protobuf behavior
- 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
- Document the four accepted values wherever you document your OTel collector setup
- Beware YAML/CI quoting that wraps values in extra quotes
- Default to unsetting the var when in doubt — http/protobuf is the default
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
- Env var OTEL_TRACES_SAMPLER specifies an unsupported sampler
- Failed to read env var OTEL_EXPORTER_OTLP_PROTOCOL
- Invalid value for…
- must be unset or set to 1
- failed to set otel globals
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)