From 778d730d290bf6b15c0a92cb34a4333036f3ac5b Mon Sep 17 00:00:00 2001 From: Benjamin De Bernardi Date: Wed, 24 Dec 2025 18:10:34 +0100 Subject: [PATCH 1/4] chore(doc): add documentation clearly stating that tracer.ContextWithSpan panics --- ddtrace/tracer/context.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ddtrace/tracer/context.go b/ddtrace/tracer/context.go index f33f0048a8b..736d2ebb549 100644 --- a/ddtrace/tracer/context.go +++ b/ddtrace/tracer/context.go @@ -15,6 +15,8 @@ import ( ) // ContextWithSpan returns a copy of the given context which includes the span s. +// +// ctx must be non-nil. If ctx is nil, context.WithValue panics, "cannot create context from nil parent". func ContextWithSpan(ctx context.Context, s *Span) context.Context { newCtx := orchestrion.CtxWithValue(ctx, internal.ActiveSpanKey, s) return contextWithPropagatedLLMSpan(newCtx, s) From 2a044fce6734c78512cdbee7dc07deabf3ca10d3 Mon Sep 17 00:00:00 2001 From: Benjamin De Bernardi Date: Thu, 26 Mar 2026 17:09:25 +0100 Subject: [PATCH 2/4] feat(tracer): add explicit nil-check panic in ContextWithSpan --- ddtrace/tracer/context.go | 5 ++++- ddtrace/tracer/context_test.go | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ddtrace/tracer/context.go b/ddtrace/tracer/context.go index 736d2ebb549..d121363a8da 100644 --- a/ddtrace/tracer/context.go +++ b/ddtrace/tracer/context.go @@ -16,8 +16,11 @@ import ( // ContextWithSpan returns a copy of the given context which includes the span s. // -// ctx must be non-nil. If ctx is nil, context.WithValue panics, "cannot create context from nil parent". +// ctx must be non-nil. Panics if ctx is nil. func ContextWithSpan(ctx context.Context, s *Span) context.Context { + if ctx == nil { + panic("ContextWithSpan: ctx cannot be nil") + } newCtx := orchestrion.CtxWithValue(ctx, internal.ActiveSpanKey, s) return contextWithPropagatedLLMSpan(newCtx, s) } diff --git a/ddtrace/tracer/context_test.go b/ddtrace/tracer/context_test.go index a6b4ad952f2..5d318a62126 100644 --- a/ddtrace/tracer/context_test.go +++ b/ddtrace/tracer/context_test.go @@ -24,6 +24,12 @@ func TestContextWithSpan(t *testing.T) { assert.Equal(got, want) } +func TestContextWithSpanNilPanics(t *testing.T) { + assert.PanicsWithValue(t, "ContextWithSpan: ctx cannot be nil", func() { + ContextWithSpan(nil, &Span{spanID: 123}) + }) +} + func TestSpanFromContext(t *testing.T) { t.Run("regular", func(t *testing.T) { assert := assert.New(t) From c1b5473963ed779c37a1f15c807e9b3a5781c4dc Mon Sep 17 00:00:00 2001 From: Benjamin De Bernardi Date: Fri, 27 Mar 2026 14:42:56 +0100 Subject: [PATCH 3/4] fix(tracer): use background context instead of panicking on nil ctx in ContextWithSpan --- ddtrace/tracer/context.go | 7 ++++--- ddtrace/tracer/context_test.go | 24 +++++++++++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/ddtrace/tracer/context.go b/ddtrace/tracer/context.go index d121363a8da..f86cce575b4 100644 --- a/ddtrace/tracer/context.go +++ b/ddtrace/tracer/context.go @@ -15,11 +15,12 @@ import ( ) // ContextWithSpan returns a copy of the given context which includes the span s. -// -// ctx must be non-nil. Panics if ctx is nil. +// If ctx is nil, a new background context is created to avoid panicking. func ContextWithSpan(ctx context.Context, s *Span) context.Context { if ctx == nil { - panic("ContextWithSpan: ctx cannot be nil") + // default to context.Background() to avoid panics on Go >= 1.15 + // The underlying context.WithValue function panics on nil context + ctx = context.Background() } newCtx := orchestrion.CtxWithValue(ctx, internal.ActiveSpanKey, s) return contextWithPropagatedLLMSpan(newCtx, s) diff --git a/ddtrace/tracer/context_test.go b/ddtrace/tracer/context_test.go index 5d318a62126..3e98bb613fc 100644 --- a/ddtrace/tracer/context_test.go +++ b/ddtrace/tracer/context_test.go @@ -17,16 +17,22 @@ import ( ) func TestContextWithSpan(t *testing.T) { - want := &Span{spanID: 123} - ctx := ContextWithSpan(context.Background(), want) - got := ctx.Value(internal.ActiveSpanKey) - assert := assert.New(t) - assert.Equal(got, want) -} + t.Run("OK", func(t *testing.T) { + want := &Span{spanID: 123} + ctx := ContextWithSpan(context.Background(), want) + got := ctx.Value(internal.ActiveSpanKey) + assert := assert.New(t) + assert.Equal(got, want) + }) -func TestContextWithSpanNilPanics(t *testing.T) { - assert.PanicsWithValue(t, "ContextWithSpan: ctx cannot be nil", func() { - ContextWithSpan(nil, &Span{spanID: 123}) + t.Run("nil context", func(t *testing.T) { + assert.NotPanics(t, func() { + want := &Span{spanID: 123} + ctx := ContextWithSpan(nil, want) + got := ctx.Value(internal.ActiveSpanKey) + assert := assert.New(t) + assert.Equal(got, want) + }) }) } From 59b7717676c2930d90868e939bab5b58645d6677 Mon Sep 17 00:00:00 2001 From: Benjamin De Bernardi Date: Mon, 30 Mar 2026 10:12:09 +0200 Subject: [PATCH 4/4] fix(tracer): add warn log on nil context in ContextWithSpan --- ddtrace/tracer/context.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ddtrace/tracer/context.go b/ddtrace/tracer/context.go index f86cce575b4..78e830cfe78 100644 --- a/ddtrace/tracer/context.go +++ b/ddtrace/tracer/context.go @@ -11,6 +11,7 @@ import ( "github.com/DataDog/dd-trace-go/v2/instrumentation/options" "github.com/DataDog/dd-trace-go/v2/internal" illmobs "github.com/DataDog/dd-trace-go/v2/internal/llmobs" + "github.com/DataDog/dd-trace-go/v2/internal/log" "github.com/DataDog/dd-trace-go/v2/internal/orchestrion" ) @@ -18,8 +19,7 @@ import ( // If ctx is nil, a new background context is created to avoid panicking. func ContextWithSpan(ctx context.Context, s *Span) context.Context { if ctx == nil { - // default to context.Background() to avoid panics on Go >= 1.15 - // The underlying context.WithValue function panics on nil context + log.Warn("ContextWithSpan: received nil context, falling back to context.Background()") ctx = context.Background() } newCtx := orchestrion.CtxWithValue(ctx, internal.ActiveSpanKey, s)