From af789d9bd18a3834a94e536629739470a78467bb Mon Sep 17 00:00:00 2001 From: liuhy Date: Wed, 17 Jun 2026 14:20:49 +0800 Subject: [PATCH] fix(otel): fix metadataSupplier Get/Set type mismatch breaking trace propagation Set stored values as string but Get expected []string, causing type assertion failure when OTel propagator Inject followed by Extract. Trace context (traceparent etc.) was lost during propagation. - Set: store []string{value} instead of string, consistent with triple's generateAttachments which stores http.Header values as []string - Get: add defensive string type handling alongside []string, matching RPCInvocation.GetAttachment's pattern for robustness Co-Authored-By: Claude --- filter/otel/trace/attachment.go | 17 +++++++----- filter/otel/trace/attachment_test.go | 40 +++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/filter/otel/trace/attachment.go b/filter/otel/trace/attachment.go index f6d88e76ec..f344dada28 100644 --- a/filter/otel/trace/attachment.go +++ b/filter/otel/trace/attachment.go @@ -39,21 +39,26 @@ func (s *metadataSupplier) Get(key string) string { if s.metadata == nil { return "" } - item, ok := s.metadata[key].([]string) - if !ok { + val, ok := s.metadata[key] + if !ok || val == nil { return "" } - if len(item) == 0 { - return "" + // Handle []string (produced by triple's generateAttachments and by Set below) + if item, ok := val.([]string); ok && len(item) > 0 { + return item[0] + } + // Handle string (defensive: for any externally-set string values) + if str, ok := val.(string); ok { + return str } - return item[0] + return "" } func (s *metadataSupplier) Set(key string, value string) { if s.metadata == nil { s.metadata = map[string]any{} } - s.metadata[key] = value + s.metadata[key] = []string{value} } func (s *metadataSupplier) Keys() []string { diff --git a/filter/otel/trace/attachment_test.go b/filter/otel/trace/attachment_test.go index b3f80df44d..4cfca8db6c 100644 --- a/filter/otel/trace/attachment_test.go +++ b/filter/otel/trace/attachment_test.go @@ -110,13 +110,29 @@ func Test_metadataSupplier_Get(t *testing.T) { want: "", }, { - name: "test", + name: "slice value", metadata: map[string]any{ "key": []string{"test"}, }, key: "key", want: "test", }, + { + name: "string value (defensive read)", + metadata: map[string]any{ + "key": "test", + }, + key: "key", + want: "test", + }, + { + name: "non-string non-slice value", + metadata: map[string]any{ + "key": 123, + }, + key: "key", + want: "", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -129,3 +145,25 @@ func Test_metadataSupplier_Get(t *testing.T) { }) } } + +func Test_metadataSupplier_SetGetRoundTrip(t *testing.T) { + // This is the core bug scenario: Set stores a value, Get must be able to read it back. + s := &metadataSupplier{ + metadata: map[string]any{}, + } + s.Set("traceparent", "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01") + + got := s.Get("traceparent") + if got != "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" { + t.Errorf("round-trip Get() = %q, want traceparent value", got) + } + + // Verify the stored type is []string, consistent with triple's generateAttachments + stored, ok := s.metadata["traceparent"].([]string) + if !ok { + t.Errorf("Set stored type %T, want []string", s.metadata["traceparent"]) + } + if len(stored) != 1 || stored[0] != "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" { + t.Errorf("stored value = %v, want [traceparent]", stored) + } +}