Skip to content

[BUG]: opentelemetry span.End() overrides user-set error fields (error.message, error.type, error.stack) #3708

@kmrgirish

Description

@kmrgirish

Tracer Version(s)

all versions <= v2.0.1

Go Version(s)

go1.24.3 darwin/arm64

Bug Report

We’re using the Datadog OpenTelemetry bridge with the OpenTelemetry Go SDK. We noticed that when we manually set error.message, error.type, and error.stack, these fields are overwritten during span.End() if the span status is set to Error.

if s.statusInfo.code == otelcodes.Error {
s.DD.SetTag(ext.ErrorMsg, s.statusInfo.description)
opts = append(opts, tracer.WithError(errors.New(s.statusInfo.description)))
}

case error:
// if anyone sets an error value as the tag, be nice here
// and provide all the benefits.
setError(true)
s.setMeta(ext.ErrorMsg, v.Error())
s.setMeta(ext.ErrorType, reflect.TypeOf(v).String())
if !cfg.noDebugStack {
s.setMeta(ext.ErrorStack, takeStacktrace(cfg.stackFrames, cfg.stackSkip))
}

This behavior causes our manually attached error metadata to be lost — most notably error.stack, which gets replaced by a stack trace pointing to internal middleware like interceptors or gRPC handlers, rather than our application’s actual error context.

Stack trace example
Here is a sample where you can see the overwritten stack trace originating from middleware:

gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer.(*span).setTagError
	/go/pkg/mod/gopkg.in/!data!dog/[email protected]/ddtrace/tracer/span.go:332
gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer.(*span).Finish
	/go/pkg/mod/gopkg.in/!data!dog/[email protected]/ddtrace/tracer/span.go:477
gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentelemetry.(*span).End
	/go/pkg/mod/gopkg.in/!data!dog/[email protected]/ddtrace/opentelemetry/span.go:103
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc.(*config).handleRPC
	/go/pkg/mod/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/[email protected]/stats_handler.go:204
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc.(*serverHandler).HandleRPC
	/go/pkg/mod/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/[email protected]/stats_handler.go:81
google.golang.org/grpc.(*Server).processUnaryRPC.func1
	/go/pkg/mod/google.golang.org/[email protected]/server.go:1262
google.golang.org/grpc.(*Server).processUnaryRPC
	/go/pkg/mod/google.golang.org/[email protected]/server.go:1427
google.golang.org/grpc.(*Server).handleStream
	/go/pkg/mod/google.golang.org/[email protected]/server.go:1802
google.golang.org/grpc.(*Server).serveStreams.func2.1
	/go/pkg/mod/google.golang.org/[email protected]/server.go:1030
runtime.goexit
	/usr/local/go/src/runtime/asm_amd64.s:1700

This is not helpful when trying to debug real issues from user code.


Expected behavior

If a user has already set error.message, error.type, or error.stack, the tracer should not overwrite them. These fields should be treated as user-defined and preserved.

Actual behavior

When a span ends with status code = Error, the ddotel implementation internally creates a new error using the statusInfo.description, and calls tracer.WithError(...). This leads to:

  • Overwriting error.message with the statusInfo.description
  • Overwriting error.type using reflect.TypeOf(error)
  • Overwriting error.stack with a new stack trace — which, in our case, only includes internal tracing layers, not the actual error origin

We are currently using [email protected]. I also checked the [email protected] — while we haven’t tested it in our setup yet, the codebase appears to follow the same logic, so the issue likely persists in v2 as well.

This issue appears to be related to #3424, which highlights a similar problem regarding error field overwriting.

Reproduction Code

No response

Error Logs

No response

Go Env Output

No response

Metadata

Metadata

Assignees

Labels

bugunintended behavior that has to be fixed

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions