{"record":{"id":"7864c0c7cd1e7610","repo":"denoland/deno","slug":"env-var-otel-exporter-otlp-protocol-specifies-an-u","errorCode":null,"errorMessage":"Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an unsupported protocol: {}","messagePattern":"Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an unsupported protocol: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ext/telemetry/lib.rs","lineNumber":1254,"sourceCode":"\n  // Parse the `OTEL_EXPORTER_OTLP_PROTOCOL` variable. The opentelemetry_*\n  // crates don't do this automatically.\n  // `opentelemetry_otlp::Protocol::Grpc` is feature-gated behind the\n  // (tonic-based) `grpc-tonic` feature, which we don't enable because we ship\n  // our own gRPC framing. Track the gRPC choice with a separate flag so the\n  // `protocol` value is only ever the HTTP variant passed to the OTLP HTTP\n  // exporter builder.\n  let protocol_var = sys.env_var(\"OTEL_EXPORTER_OTLP_PROTOCOL\");\n  let (use_console_exporter, use_grpc, protocol) = match protocol_var.as_deref()\n  {\n    Ok(\"console\") => (true, false, Protocol::HttpBinary),\n    Ok(\"http/protobuf\") | Ok(\"\") | Err(std::env::VarError::NotPresent) => {\n      (false, false, Protocol::HttpBinary)\n    }\n    Ok(\"http/json\") => (false, false, Protocol::HttpJson),\n    Ok(\"grpc\") => (false, true, Protocol::HttpBinary),\n    Ok(protocol) => {\n      return Err(deno_core::anyhow::anyhow!(\n        \"Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an unsupported protocol: {}\",\n        protocol\n      ));\n    }\n    Err(err) => {\n      return Err(deno_core::anyhow::anyhow!(\n        \"Failed to read env var OTEL_EXPORTER_OTLP_PROTOCOL: {}\",\n        err\n      ));\n    }\n  };\n\n  // Define the resource attributes that will be attached to all log records.\n  // These attributes are sourced as follows (in order of precedence):\n  //   * The `service.name` attribute from the `OTEL_SERVICE_NAME` env var.\n  //   * Additional attributes from the `OTEL_RESOURCE_ATTRIBUTES` env var.\n  //   * Default attribute values defined here.\n  // TODO(piscisaureus): add more default attributes (e.g. script path).","sourceCodeStart":1236,"sourceCodeEnd":1272,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/telemetry/lib.rs#L1236-L1272","documentation":"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.","triggerScenarios":"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\"'.","commonSituations":"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.","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"],"exampleFix":"# before\nexport OTEL_EXPORTER_OTLP_PROTOCOL=HTTP/JSON  # -> unsupported protocol\ndeno run --otel app.ts\n\n# after\nexport OTEL_EXPORTER_OTLP_PROTOCOL=http/json\ndeno run --otel app.ts","handlingStrategy":"validation","validationCode":"const ALLOWED_PROTOCOLS = new Set([\"\", \"console\", \"http/protobuf\", \"http/json\", \"grpc\"]);\nconst proto = Deno.env.get(\"OTEL_EXPORTER_OTLP_PROTOCOL\") ?? \"\";\nif (!ALLOWED_PROTOCOLS.has(proto)) {\n  throw new Error(`OTEL_EXPORTER_OTLP_PROTOCOL='${proto}' must be one of: ${[...ALLOWED_PROTOCOLS].join(\", \")}`);\n}","typeGuard":null,"tryCatchPattern":"const { code, stderr } = await new Deno.Command(\"deno\", { args: [\"run\", \"--otel\", \"app.ts\"] }).output();\nif (code !== 0 && new TextDecoder().decode(stderr).includes(\"unsupported protocol\")) {\n  delete env.OTEL_EXPORTER_OTLP_PROTOCOL; // fall back to default http/protobuf\n  // relaunch\n}","preventionTips":["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"],"tags":["otel","otlp","exporter","env-var","configuration","startup"],"backgroundTag":"invalid-env-var-value","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}