{"record":{"id":"bd632989637d482b","repo":"denoland/deno","slug":"failed-to-set-otel-globals","errorCode":null,"errorMessage":"failed to set otel globals","messagePattern":"failed to set otel globals","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ext/telemetry/lib.rs","lineNumber":1423,"sourceCode":"  let span_attribute_count_limit = span_attribute_count_limit_from_env(sys);\n  let span_attribute_value_length_limit =\n    span_attribute_value_length_limit_from_env(sys);\n  let sampler = Sampler::from_env(sys)?;\n\n  OTEL_GLOBALS\n    .set(OtelGlobals {\n      log_processor,\n      span_processor,\n      id_generator,\n      meter_provider,\n      builtin_instrumentation_scope,\n      span_event_count_limit,\n      span_attribute_count_limit,\n      span_attribute_value_length_limit,\n      sampler,\n      config,\n    })\n    .map_err(|_| deno_core::anyhow::anyhow!(\"failed to set otel globals\"))?;\n\n  deno_signals::before_exit(before_exit);\n  deno_net::tunnel::disable_before_exit();\n\n  Ok(())\n}\n\nfn before_exit() {\n  log::trace!(\"deno_telemetry::before_exit\");\n\n  let Some(OtelGlobals {\n    span_processor: spans,\n    log_processor: logs,\n    meter_provider,\n    ..\n  }) = OTEL_GLOBALS.get()\n  else {\n    return;","sourceCodeStart":1405,"sourceCodeEnd":1441,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/telemetry/lib.rs#L1405-L1441","documentation":"Deno stores its initialized telemetry state (processors, meter provider, sampler, limits) in a global OnceCell. Setting that cell fails — yielding 'failed to set otel globals' — if telemetry globals were already populated, i.e. the OTEL setup path executed a second time in the same process. This is an internal double-initialization guard, not an environment-configuration problem.","triggerScenarios":"Embedding deno_core/deno_runtime and calling the telemetry init (configure_opentelemetry-style entry point) twice; a Deno version regression where a worker or snapshot path re-runs OTel setup; runtime customization code that installs OTel globals before Deno's own --otel startup path runs.","commonSituations":"Custom embedders (runtime builders on top of deno_core) that add their own OTel bootstrap; upgrading Deno versions where init ordering changed; tests that boot multiple JsRuntimes in one process with --otel semantics each time.","solutions":["Ensure the telemetry/global-OTel setup runs exactly once per process (guard it behind your own OnceCell or lazy static)","If you embed Deno, don't call the OTel init API yourself and also pass --otel; pick one owner","Update to the latest Deno patch release — double-init in standard `deno` CLI flows is a bug worth reporting at https://github.com/denoland/deno/issues","As a workaround, drop the custom OTel env/flags in the second init site so only the first initializes globals"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Embedders: guard so OTel globals init at most once per process\nuse std::sync::Once;\nstatic OTEL_INIT: Once = Once::new();\nfn init_telemetry_once(sys: &impl TelemetrySys) -> anyhow::Result<()> {\n    // First caller initializes; later callers are no-ops, avoiding the\n    // OnceCell double-set that produces \"failed to set otel globals\".\n    let mut first_err: Option<anyhow::Error> = None;\n    OTEL_INIT.call_once(|| {\n        if let Err(e) = deno_telemetry::init(sys) { first_err = Some(e); }\n    });\n    first_err.map_or(Ok(()), Err)\n}","typeGuard":null,"tryCatchPattern":"// In embedder bootstrap code\nmatch deno_telemetry::init(&sys) {\n    Err(e) if e.to_string().contains(\"failed to set otel globals\") => {\n        // Globals already installed by an earlier init: log and continue\n        log::warn!(\"otel globals already set; skipping re-init\");\n    }\n    other => other?,\n}","preventionTips":["Never call the telemetry init API from two places (CLI --otel path and embedder bootstrap)","Wrap global installs in Once/OnceCell at the call site, since the internal set is not idempotent","For multi-runtime test harnesses, run each --otel runtime in its own process"],"tags":["otel","initialization","once-only","globals","internal","startup"],"backgroundTag":"double-initialization","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"}