Repository: denoland/deno (language: rust)

Issue:
OTEL root context is undefined by default
Version: Deno 2.2.1

Trying to run simple code using OTEL api:
```ts
import { trace } from 'npm:@opentelemetry/api@1';

const a = trace.getTracer('foo');

a.startActiveSpan('bar', span => {
	span.addEvent('baz');
	span.end();
});
```

```shell
$ deno run --unstable-otel -A demo.ts 
error: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'setValue')
a.startActiveSpan('bar', span => {
  ^
    at Tracer.startActiveSpan (ext:deno_telemetry/telemetry.ts:76:39)
    at file:///path/to/demo.ts:5:3
```

Because there is no active root context at this point

Only when entered manually:
```ts
import { trace, context } from 'npm:@opentelemetry/api@1';

const root = context.active();
const a = trace.getTracer('foo');

context.with(root, () => {
	a.startActiveSpan('bar', span => {
		span.addEvent('baz');
		span.end();
	});
});
```
This code runs successfully.


Discussion / hints:

Fix patch:
diff --git a/ext/telemetry/telemetry.ts b/ext/telemetry/telemetry.ts
index 139affbf47e36e..50983def638004 100644
--- a/ext/telemetry/telemetry.ts
+++ b/ext/telemetry/telemetry.ts
@@ -145,7 +145,7 @@ function hrToMs(hr: [number, number]): number {
 
 export function enterSpan(span: Span): Context | undefined {
   if (!span.isRecording()) return undefined;
-  const context = (CURRENT.get() || ROOT_CONTEXT).setValue(SPAN_KEY, span);
+  const context = (CURRENT.get() ?? ROOT_CONTEXT).setValue(SPAN_KEY, span);
   return CURRENT.enter(context);
 }
 
@@ -254,9 +254,9 @@ class Tracer {
       throw new Error("startActiveSpan requires a function argument");
     }
     if (options?.root) {
-      context = undefined;
+      context = ROOT_CONTEXT;
     } else {
-      context = context ?? CURRENT.get();
+      context = context ?? CURRENT.get() ?? ROOT_CONTEXT;
     }
     const span = this.startSpan(name, options, context);
     const ctx = CURRENT.enter(context.setValue(SPAN_KEY, span));


Test patch:
diff --git a/tests/specs/cli/otel_basic/__test__.jsonc b/tests/specs/cli/otel_basic/__test__.jsonc
index d538eac736fccb..18d5e668cef868 100644
--- a/tests/specs/cli/otel_basic/__test__.jsonc
+++ b/tests/specs/cli/otel_basic/__test__.jsonc
@@ -33,6 +33,10 @@
     "links": {
       "args": "run -A main.ts links.ts",
       "output": "links.out"
+    },
+    "start_active_span": {
+      "args": "run -A main.ts start_active_span.ts",
+      "output": "start_active_span.out"
     }
   }
 }
diff --git a/tests/specs/cli/otel_basic/start_active_span.out b/tests/specs/cli/otel_basic/start_active_span.out
new file mode 100644
index 00000000000000..1b19ee5d448bd2
--- /dev/null
+++ b/tests/specs/cli/otel_basic/start_active_span.out
@@ -0,0 +1,48 @@
+{
+  "spans": [
+    {
+      "traceId": "00000000000000000000000000000001",
+      "spanId": "0000000000000001",
+      "traceState": "",
+      "parentSpanId": "",
+      "flags": 1,
+      "name": "top level span",
+      "kind": 1,
+      "startTimeUnixNano": "[WILDCARD]",
+      "endTimeUnixNano": "[WILDCARD]",
+      "attributes": [],
+      "droppedAttributesCount": 0,
+      "events": [],
+      "droppedEventsCount": 0,
+      "links": [],
+      "droppedLinksCount": 0,
+      "status": {
+        "message": "",
+        "code": 0
+      }
+    },
+    {
+      "traceId": "00000000000000000000000000000002",
+      "spanId": "0000000000000002",
+      "traceState": "",
+      "parentSpanId": "",
+      "flags": 1,
+      "name": "root span",
+      "kind": 1,
+      "startTimeUnixNano": "[WILDCARD]",
+      "endTimeUnixNano": "[WILDCARD]",
+      "attributes": [],
+      "droppedAttributesCount": 0,
+      "events": [],
+      "droppedEventsCount": 0,
+      "links": [],
+      "droppedLinksCount": 0,
+      "status": {
+        "message": "",
+        "code": 0
+      }
+    }
+  ],
+  "logs": [],
+  "metrics": []
+}
diff --git a/tests/specs/cli/otel_basic/start_active_span.ts b/tests/specs/cli/otel_basic/start_active_span.ts
new file mode 100644
index 00000000000000..8dd91df8d00987
--- /dev/null
+++ b/tests/specs/cli/otel_basic/start_active_span.ts
@@ -0,0 +1,12 @@
+// Copyright 2018-2025 the Deno authors. MIT license.
+
+import { trace } from "npm:@opentelemetry/api@1.9.0";
+
+const tracer = trace.getTracer("example-tracer");
+
+tracer.startActiveSpan("top level span", (span) => {
+  span.end();
+});
+tracer.startActiveSpan("root span", { root: true }, (span) => {
+  span.end();
+});