denoland/deno · error · anyhow::Error
Failed to read env var OTEL_EXPORTER_OTLP_PROTOCOL
Error message
Failed to read env var OTEL_EXPORTER_OTLP_PROTOCOL: {} What it means
When reading OTEL_EXPORTER_OTLP_PROTOCOL, Deno distinguishes two failure modes: the variable being absent (VarError::NotPresent, treated as default) and every other std::env::VarError — practically only VarError::NotUnicode, i.e. the environment variable holds bytes that are not valid UTF-8. Since Rust env vars are OsString-backed, a non-UTF-8 value aborts telemetry init with this wrapped error.
Solutions
- Re-set the variable with a plain ASCII value: OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
- Unset it entirely (absent is handled as the default, only invalid bytes are fatal)
- Recreate the env_file / secret as UTF-8 text (use stringData rather than data in Kubernetes secrets)
Example fix
# before (env file saved as Latin-1 with BOM-like bytes) docker run --env-file .env deno --otel app.ts # after: rewrite file as UTF-8 with a clean value printf 'OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf\n' > .env docker run --env-file .env deno --otel app.ts
Defensive patterns
Strategy: validation
Validate before calling
# Fail fast in the launch script if the var holds non-UTF-8 bytes
if [ "${OTEL_EXPORTER_OTLP_PROTOCOL+x}" != "x" ]; then
unset OTEL_EXPORTER_OTLP_PROTOCOL
elif ! printf '%s' "$OTEL_EXPORTER_OTLP_PROTOCOL" | LC_ALL=C grep -qP '^[\x00-\x7F]*$'; then
echo "OTEL_EXPORTER_OTLP_PROTOCOL is not valid UTF-8/ASCII; resetting" >&2
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
fi Prevention
- Create env files and Kubernetes secrets as UTF-8 text (stringData, not binary data)
- Avoid passing env through legacy Windows codepages; set vars from a UTF-8 shell or script
- When in doubt, re-export the variable explicitly right before launching deno
When it happens
Trigger: A process whose environment contains OTEL_EXPORTER_OTLP_PROTOCOL encoded in a non-UTF-8 codepage (e.g. Latin-1 bytes from a legacy Windows shell) or binary garbage injected by a misconfigured secrets agent or CI variable-passing mechanism.
Common situations: Windows CMD/PowerShell writing env vars with legacy encodings; Docker env_file saved with a non-UTF-8 editor; Kubernetes secrets created from binary data instead of stringData; shell scripts sourced from files with broken encoding.
Related errors
- Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an…
- Env var OTEL_TRACES_SAMPLER specifies an unsupported sampler
- 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/fc615971faaea356.
Report an issue: GitHub.
Appendix: 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 9ad36f7a2c)