Repository: jaegertracing/jaeger

Issue:
Clean up dependabot config
We are mostly using Renovate bot for upgrades, configured via `renovate.json`. But we also have Dependabot enabled (`.github/dependabot.yml`) that sometimes creates redundant PRs.

Objective:
  * Compare Dependabot config to see if it as anything not covered by Renovate and remove redundant entries
  * Definitely remove Go entries

Hints from issue comments:
@jinjiaKarl: Hi, I am interested in this. Could you assign it to me?@yurishkuro: go for it@jinjiaKarl: I am confused about the objectives.

Since you mentioned the "Compare Dependabot config to see if it as anything not covered by Renovate", if there is something covered by Dependabot but not Renovate, should we move it to Renovate. In this sense, dependabot can be removed.
@yurishkuro: Let's do the comparison and then decide 

Solution patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index d563bf0a..00000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,81 +0,0 @@
-version: 2
-updates:
-  - package-ecosystem: gomod
-    directory: "/"
-    schedule:
-      interval: daily
-    open-pull-requests-limit: 10
-    labels: [ "changelog:dependencies" ]
-    # Groups are updated together in one pull request
-    groups:
-      otel:
-        patterns:
-          - "go.opentelemetry.io/otel*"
-      otel-collector:
-        patterns:
-          - "go.opentelemetry.io/collector*"
-          - "github.com/open-telemetry/o*-collector-contrib/*"
-      otel-instrumentation:
-        patterns:
-          - "go.opentelemetry.io/contrib/instrumentation/*"
-
-  - package-ecosystem: gomod
-    directory: "/internal/tools"
-    schedule:
-      interval: daily
-    labels: [ "changelog:dependencies" ]
-
-  - package-ecosystem: docker
-    directories:
-      - /cmd/agent
-      - /cmd/all-in-one
-      - /cmd/anonymizer
-      - /cmd/collector
-      - /cmd/es-index-cleaner
-      - /cmd/es-rollover
-      - /cmd/ingester
-      - /cmd/jaeger
-      - /cmd/query
-      - /cmd/remote-storage
-      - /cmd/tracegen
-      - /crossdock
-      - /docker/base
-      - /docker/debug
-      - /examples/hotrod
-      - /internal/storage/v1/cassandra
-    schedule:
-      interval: daily
-  - package-ecosystem: docker
-    directories:
-      - /docker-compose/elasticsearch/v7
-      - /docker-compose/elasticsearch/v8
-    schedule:
-      interval: daily
-    ignore:
-      - dependency-name: "docker.elastic.co/elasticsearch/elasticsearch"
-        update-types: [ "version-update:semver-major" ]
-  - package-ecosystem: docker
-    directories:
-      - /docker-compose/opensearch/v1
-      - /docker-compose/opensearch/v2
-    schedule:
-      interval: daily
-    ignore:
-      - dependency-name: "opensearchproject/opensearch"
-        update-types: [ "version-update:semver-major" ]
-  - package-ecosystem: docker
-    directory: /docker-compose/kafka-integration-test
-    schedule:
-      interval: daily
-    ignore:
-      - dependency-name: "bitnami/kafka"
-        update-types: [ "version-update:semver-major" ]
-  - package-ecosystem: docker
-    directories:
-      - /docker-compose/cassandra/v4
-      - /docker-compose/cassandra/v5
-    schedule:
-      interval: daily
-    ignore:
-      - dependency-name: "cassandra"
-        update-types: [ "version-update:semver-major" ]
diff --git a/internal/storage/v1/elasticsearch/spanstore/core_span_reader.go b/internal/storage/v1/elasticsearch/spanstore/core_span_reader.go
index 0764ee94..fa148c5c 100644
--- a/internal/storage/v1/elasticsearch/spanstore/core_span_reader.go
+++ b/internal/storage/v1/elasticsearch/spanstore/core_span_reader.go
@@ -14,9 +14,9 @@ import (
 // CoreSpanReader is a DB-Level abstraction which directly deals with database level operations
 type CoreSpanReader interface {
 	// FindTraceIDs retrieves traces IDs that match the traceQuery
-	FindTraceIDs(ctx context.Context, traceQuery *spanstore.TraceQueryParameters) ([]model.TraceID, error)
+	FindTraceIDs(ctx context.Context, traceQuery *dbmodel.TraceQueryParameters) ([]dbmodel.TraceID, error)
 	// FindTraces retrieves traces that match the traceQuery
-	FindTraces(ctx context.Context, traceQuery *spanstore.TraceQueryParameters) ([]*model.Trace, error)
+	FindTraces(ctx context.Context, traceQuery *dbmodel.TraceQueryParameters) ([]*model.Trace, error)
 	// GetOperations returns all operations for a specific service traced by Jaeger
 	GetOperations(ctx context.Context, query dbmodel.OperationQueryParameters) ([]dbmodel.Operation, error)
 	// GetServices returns all services traced by Jaeger, ordered by frequency
diff --git a/internal/storage/v1/elasticsearch/spanstore/internal/dbmodel/model.go b/internal/storage/v1/elasticsearch/spanstore/internal/dbmodel/model.go
index a5016eea..927385b0 100644
--- a/internal/storage/v1/elasticsearch/spanstore/internal/dbmodel/model.go
+++ b/internal/storage/v1/elasticsearch/spanstore/internal/dbmodel/model.go
@@ -4,6 +4,8 @@
 
 package dbmodel
 
+import "time"
+
 // ReferenceType is the reference type of one span to another
 type ReferenceType string
 
@@ -100,3 +102,16 @@ type OperationQueryParameters struct {
 	ServiceName string
 	SpanKind    string
 }
+
+// TraceQueryParameters contains parameters of a trace query.
+type TraceQueryParameters struct {
+	ServiceName   string
+	OperationName string
+	Tags          map[string]string
+	StartTimeMin  time.Time
+	StartTimeMax  time.Time
+	DurationMin   time.Duration
+	DurationMax   time.Duration
+	// TODO: Rename NumTraces to SearchDepth
+	NumTraces int
+}
diff --git a/internal/storage/v1/elasticsearch/spanstore/mocks/CoreSpanReader.go b/internal/storage/v1/elasticsearch/spanstore/mocks/CoreSpanReader.go
index 07f56695..34cbb6ec 100644
--- a/internal/storage/v1/elasticsearch/spanstore/mocks/CoreSpanReader.go
+++ b/internal/storage/v1/elasticsearch/spanstore/mocks/CoreSpanReader.go
@@ -10,13 +10,13 @@ package mocks
 import (
 	context "context"
 
+	apispanstore "github.com/jaegertracing/jaeger/internal/storage/v1/api/spanstore"
+
 	dbmodel "github.com/jaegertracing/jaeger/internal/storage/v1/elasticsearch/spanstore/internal/dbmodel"
 
 	mock "github.com/stretchr/testify/mock"
 
 	model "github.com/jaegertracing/jaeger-idl/model/v1"
-
-	spanstore "github.com/jaegertracing/jaeger/internal/storage/v1/api/spanstore"
 )
 
 // CoreSpanReader is an autogenerated mock type for the CoreSpanReader type
@@ -25,27 +25,27 @@ type CoreSpanReader struct {
 }
 
 // FindTraceIDs provides a mock function with given fields: ctx, traceQuery
-func (_m *CoreSpanReader) FindTraceIDs(ctx context.Context, traceQuery *spanstore.TraceQueryParameters) ([]model.TraceID, error) {
+func (_m *CoreSpanReader) FindTraceIDs(ctx context.Context, traceQuery *dbmodel.TraceQueryParameters) ([]dbmodel.TraceID, error) {
 	ret := _m.Called(ctx, traceQuery)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FindTraceIDs")
 	}
 
-	var r0 []model.TraceID
+	var r0 []dbmodel.TraceID
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *spanstore.TraceQueryParameters) ([]model.TraceID, error)); ok {
+	if rf, ok := ret.Get(0).(func(context.Context, *dbmodel.TraceQueryParameters) ([]dbmodel.TraceID, error)); ok {
 		return rf(ctx, traceQuery)
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *spanstore.TraceQueryParameters) []model.TraceID); ok {
+	if rf, ok := ret.Get(0).(func(context.Context, *dbmodel.TraceQueryParameters) []dbmodel.TraceID); ok {
 		r0 = rf(ctx, traceQuery)
 	} else {
 		if ret.Get(0) != nil {
-			r0 = ret.Get(0).([]model.TraceID)
+			r0 = ret.Get(0).([]dbmodel.TraceID)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(context.Context, *spanstore.TraceQueryParameters) error); ok {
+	if rf, ok := ret.Get(1).(func(context.Context, *dbmodel.TraceQueryParameters) error); ok {
 		r1 = rf(ctx, traceQuery)
 	} else {
 		r1 = ret.Error(1)
@@ -55,7 +55,7 @@ func (_m *CoreSpanReader) FindTraceIDs(ctx context.Context, traceQuery *spanstor
 }
 
 // FindTraces provides a mock function with given fields: ctx, traceQuery
-func (_m *CoreSpanReader) FindTraces(ctx context.Context, traceQuery *spanstore.TraceQueryParameters) ([]*model.Trace, error) {
+func (_m *CoreSpanReader) FindTraces(ctx context.Context, traceQuery *dbmodel.TraceQueryParameters) ([]*model.Trace, error) {
 	ret := _m.Called(ctx, traceQuery)
 
 	if len(ret) == 0 {
@@ -64,10 +64,10 @@ func (_m *CoreSpanReader) FindTraces(ctx context.Context, traceQuery *spanstore.
 
 	var r0 []*model.Trace
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *spanstore.TraceQueryParameters) ([]*model.Trace, error)); ok {
+	if rf, ok := ret.Get(0).(func(context.Context, *dbmodel.TraceQueryParameters) ([]*model.Trace, error)); ok {
 		return rf(ctx, traceQuery)
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *spanstore.TraceQueryParameters) []*model.Trace); ok {
+	if rf, ok := ret.Get(0).(func(context.Context, *dbmodel.TraceQueryParameters) []*model.Trace); ok {
 		r0 = rf(ctx, traceQuery)
 	} else {
 		if ret.Get(0) != nil {
@@ -75,7 +75,7 @@ func (_m *CoreSpanReader) FindTraces(ctx context.Context, traceQuery *spanstore.
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(context.Context, *spanstore.TraceQueryParameters) error); ok {
+	if rf, ok := ret.Get(1).(func(context.Context, *dbmodel.TraceQueryParameters) error); ok {
 		r1 = rf(ctx, traceQuery)
 	} else {
 		r1 = ret.Error(1)
@@ -145,7 +145,7 @@ func (_m *CoreSpanReader) GetServices(ctx context.Context) ([]string, error) {
 }
 
 // GetTrace provides a mock function with given fields: ctx, query
-func (_m *CoreSpanReader) GetTrace(ctx context.Context, query spanstore.GetTraceParameters) (*model.Trace, error) {
+func (_m *CoreSpanReader) GetTrace(ctx context.Context, query apispanstore.GetTraceParameters) (*model.Trace, error) {
 	ret := _m.Called(ctx, query)
 
 	if len(ret) == 0 {
@@ -154,10 +154,10 @@ func (_m *CoreSpanReader) GetTrace(ctx context.Context, query spanstore.GetTrace
 
 	var r0 *model.Trace
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, spanstore.GetTraceParameters) (*model.Trace, error)); ok {
+	if rf, ok := ret.Get(0).(func(context.Context, apispanstore.GetTraceParameters) (*model.Trace, error)); ok {
 		return rf(ctx, query)
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, spanstore.GetTraceParameters) *model.Trace); ok {
+	if rf, ok := ret.Get(0).(func(context.Context, apispanstore.GetTraceParameters) *model.Trace); ok {
 		r0 = rf(ctx, query)
 	} else {
 		if ret.Get(0) != nil {
@@ -165,7 +165,7 @@ func (_m *CoreSpanReader) GetTrace(ctx context.Context, query spanstore.GetTrace
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(context.Context, spanstore.GetTraceParameters) error); ok {
+	if rf, ok := ret.Get(1).(func(context.Context, apispanstore.GetTraceParameters) error); ok {
 		r1 = rf(ctx, query)
 	} else {
 		r1 = ret.Error(1)
diff --git a/internal/storage/v1/elasticsearch/spanstore/reader.go b/internal/storage/v1/elasticsearch/spanstore/reader.go
index d6887ed8..7e13244d 100644
--- a/internal/storage/v1/elasticsearch/spanstore/reader.go
+++ b/internal/storage/v1/elasticsearch/spanstore/reader.go
@@ -316,20 +316,20 @@ func (s *SpanReader) GetOperations(
 	return result, err
 }
 
-func bucketToStringArray(buckets []*elastic.AggregationBucketKeyItem) ([]string, error) {
-	strings := make([]string, len(buckets))
+func bucketToStringArray[T ~string](buckets []*elastic.AggregationBucketKeyItem) ([]T, error) {
+	strings := make([]T, len(buckets))
 	for i, keyitem := range buckets {
 		str, ok := keyitem.Key.(string)
 		if !ok {
 			return nil, errors.New("non-string key found in aggregation")
 		}
-		strings[i] = str
+		strings[i] = T(str)
 	}
 	return strings, nil
 }
 
 // FindTraces retrieves traces that match the traceQuery
-func (s *SpanReader) FindTraces(ctx context.Context, traceQuery *spanstore.TraceQueryParameters) ([]*model.Trace, error) {
+func (s *SpanReader) FindTraces(ctx context.Context, traceQuery *dbmodel.TraceQueryParameters) ([]*model.Trace, error) {
 	ctx, span := s.tracer.Start(ctx, "FindTraces")
 	defer span.End()
 
@@ -337,11 +337,15 @@ func (s *SpanReader) FindTraces(ctx context.Context, traceQuery *spanstore.Trace
 	if err != nil {
 		return nil, es.DetailedError(err)
 	}
-	return s.multiRead(ctx, uniqueTraceIDs, traceQuery.StartTimeMin, traceQuery.StartTimeMax)
+	traceIds, err := toModelTraceIDs(uniqueTraceIDs)
+	if err != nil {
+		return nil, es.DetailedError(err)
+	}
+	return s.multiRead(ctx, traceIds, traceQuery.StartTimeMin, traceQuery.StartTimeMax)
 }
 
 // FindTraceIDs retrieves traces IDs that match the traceQuery
-func (s *SpanReader) FindTraceIDs(ctx context.Context, traceQuery *spanstore.TraceQueryParameters) ([]model.TraceID, error) {
+func (s *SpanReader) FindTraceIDs(ctx context.Context, traceQuery *dbmodel.TraceQueryParameters) ([]dbmodel.TraceID, error) {
 	ctx, span := s.tracer.Start(ctx, "FindTraceIDs")
 	defer span.End()
 
@@ -357,7 +361,7 @@ func (s *SpanReader) FindTraceIDs(ctx context.Context, traceQuery *spanstore.Tra
 		return nil, err
 	}
 
-	return convertTraceIDsStringsToModels(esTraceIDs)
+	return esTraceIDs, nil
 }
 
 func (s *SpanReader) multiRead(ctx context.Context, traceIDs []model.TraceID, startTime, endTime time.Time) ([]*model.Trace, error) {
@@ -477,29 +481,7 @@ func buildTraceByIDQuery(traceID model.TraceID) elastic.Query {
 		elastic.NewTermQuery(traceIDField, legacyTraceID))
 }
 
-func convertTraceIDsStringsToModels(traceIDs []string) ([]model.TraceID, error) {
-	traceIDsMap := map[model.TraceID]bool{}
-	// https://github.com/jaegertracing/jaeger/pull/1956 added leading zeros to IDs
-	// So we need to also read IDs without leading zeros for compatibility with previously saved data.
-	// That means the input to this function may contain logically identical trace IDs but formatted
-	// with or without padding, and we need to dedupe them.
-	// TODO remove deduping in newer versions, added in Jaeger 1.16
-	traceIDsModels := make([]model.TraceID, 0, len(traceIDs))
-	for _, ID := range traceIDs {
-		traceID, err := model.TraceIDFromString(ID)
-		if err != nil {
-			return nil, fmt.Errorf("making traceID from string '%s' failed: %w", ID, err)
-		}
-		if _, ok := traceIDsMap[traceID]; !ok {
-			traceIDsMap[traceID] = true
-			traceIDsModels = append(traceIDsModels, traceID)
-		}
-	}
-
-	return traceIDsModels, nil
-}
-
-func validateQuery(p *spanstore.TraceQueryParameters) error {
+func validateQuery(p *dbmodel.TraceQueryParameters) error {
 	if p == nil {
 		return ErrMalformedRequestObject
 	}
@@ -518,7 +500,7 @@ func validateQuery(p *spanstore.TraceQueryParameters) error {
 	return nil
 }
 
-func (s *SpanReader) findTraceIDs(ctx context.Context, traceQuery *spanstore.TraceQueryParameters) ([]string, error) {
+func (s *SpanReader) findTraceIDs(ctx context.Context, traceQuery *dbmodel.TraceQueryParameters) ([]dbmodel.TraceID, error) {
 	ctx, childSpan := s.tracer.Start(ctx, "findTraceIDs")
 	defer childSpan.End()
 	//  Below is the JSON body to our HTTP GET request to ElasticSearch. This function creates this.
@@ -597,7 +579,7 @@ func (s *SpanReader) findTraceIDs(ctx context.Context, traceQuery *spanstore.Tra
 		return nil, fmt.Errorf("search services failed: %w", err)
 	}
 	if searchResult.Aggregations == nil {
-		return []string{}, nil
+		return []dbmodel.TraceID{}, nil
 	}
 	bucket, found := searchResult.Aggregations.Terms(traceIDAggregation)
 	if !found {
@@ -605,7 +587,7 @@ func (s *SpanReader) findTraceIDs(ctx context.Context, traceQuery *spanstore.Tra
 	}
 
 	traceIDBuckets := bucket.Buckets
-	return bucketToStringArray(traceIDBuckets)
+	return bucketToStringArray[dbmodel.TraceID](traceIDBuckets)
 }
 
 func (s *SpanReader) buildTraceIDAggregation(numOfTraces int) elastic.Aggregation {
@@ -621,7 +603,7 @@ func (*SpanReader) buildTraceIDSubAggregation() elastic.Aggregation {
 		Field(startTimeField)
 }
 
-func (s *SpanReader) buildFindTraceIDsQuery(traceQuery *spanstore.TraceQueryParameters) elastic.Query {
+func (s *SpanReader) buildFindTraceIDsQuery(traceQuery *dbmodel.TraceQueryParameters) elastic.Query {
 	boolQuery := elastic.NewBoolQuery()
 
 	// add duration query
diff --git a/internal/storage/v1/elasticsearch/spanstore/readerv1.go b/internal/storage/v1/elasticsearch/spanstore/readerv1.go
index ea448158..74a4b97d 100644
--- a/internal/storage/v1/elasticsearch/spanstore/readerv1.go
+++ b/internal/storage/v1/elasticsearch/spanstore/readerv1.go
@@ -5,6 +5,7 @@ package spanstore
 
 import (
 	"context"
+	"fmt"
 
 	"github.com/jaegertracing/jaeger-idl/model/v1"
 	"github.com/jaegertracing/jaeger/internal/storage/v1/api/spanstore"
@@ -61,10 +62,49 @@ func (s *SpanReaderV1) GetServices(ctx context.Context) ([]string, error) {
 
 // FindTraces retrieves traces that match the traceQuery
 func (s *SpanReaderV1) FindTraces(ctx context.Context, traceQuery *spanstore.TraceQueryParameters) ([]*model.Trace, error) {
-	return s.spanReader.FindTraces(ctx, traceQuery)
+	return s.spanReader.FindTraces(ctx, toDbQueryParams(traceQuery))
 }
 
 // FindTraceIDs retrieves traces IDs that match the traceQuery
 func (s *SpanReaderV1) FindTraceIDs(ctx context.Context, traceQuery *spanstore.TraceQueryParameters) ([]model.TraceID, error) {
-	return s.spanReader.FindTraceIDs(ctx, traceQuery)
+	ids, err := s.spanReader.FindTraceIDs(ctx, toDbQueryParams(traceQuery))
+	if err != nil {
+		return nil, err
+	}
+	return toModelTraceIDs(ids)
+}
+
+func toDbQueryParams(p *spanstore.TraceQueryParameters) *dbmodel.TraceQueryParameters {
+	return &dbmodel.TraceQueryParameters{
+		ServiceName:   p.ServiceName,
+		OperationName: p.OperationName,
+		Tags:          p.Tags,
+		StartTimeMin:  p.StartTimeMin,
+		StartTimeMax:  p.StartTimeMax,
+		DurationMin:   p.DurationMin,
+		DurationMax:   p.DurationMax,
+		NumTraces:     p.NumTraces,
+	}
+}
+
+func toModelTraceIDs(traceIDs []dbmodel.TraceID) ([]model.TraceID, error) {
+	traceIDsMap := map[model.TraceID]bool{}
+	// https://github.com/jaegertracing/jaeger/pull/1956 added leading zeros to IDs
+	// So we need to also read IDs without leading zeros for compatibility with previously saved data.
+	// That means the input to this function may contain logically identical trace IDs but formatted
+	// with or without padding, and we need to dedupe them.
+	// TODO remove deduping in newer versions, added in Jaeger 1.16
+	traceIDsModels := make([]model.TraceID, 0, len(traceIDs))
+	for _, ID := range traceIDs {
+		traceID, err := model.TraceIDFromString(string(ID))
+		if err != nil {
+			return nil, fmt.Errorf("making traceID from string '%s' failed: %w", ID, err)
+		}
+		if _, ok := traceIDsMap[traceID]; !ok {
+			traceIDsMap[traceID] = true
+			traceIDsModels = append(traceIDsModels, traceID)
+		}
+	}
+
+	return traceIDsModels, nil
 }
diff --git a/internal/storage/v1/elasticsearch/spanstore/service_operation.go b/internal/storage/v1/elasticsearch/spanstore/service_operation.go
index ee9f104e..cc3e843d 100644
--- a/internal/storage/v1/elasticsearch/spanstore/service_operation.go
+++ b/internal/storage/v1/elasticsearch/spanstore/service_operation.go
@@ -87,7 +87,7 @@ func (s *ServiceOperationStorage) getServices(ctx context.Context, indices []str
 		return nil, errors.New("could not find aggregation of " + servicesAggregation)
 	}
 	serviceNamesBucket := bucket.Buckets
-	return bucketToStringArray(serviceNamesBucket)
+	return bucketToStringArray[string](serviceNamesBucket)
 }
 
 func getServicesAggregation(maxDocCount int) elastic.Query {
@@ -118,7 +118,7 @@ func (s *ServiceOperationStorage) getOperations(ctx context.Context, indices []s
 		return nil, errors.New("could not find aggregation of " + operationsAggregation)
 	}
 	operationNamesBucket := bucket.Buckets
-	return bucketToStringArray(operationNamesBucket)
+	return bucketToStringArray[string](operationNamesBucket)
 }
 
 func getOperationsAggregation(maxDocCount int) elastic.Query {



Test patch:
diff --git a/internal/storage/v1/elasticsearch/spanstore/reader_test.go b/internal/storage/v1/elasticsearch/spanstore/reader_test.go
index 38d95120..91d6250b 100644
--- a/internal/storage/v1/elasticsearch/spanstore/reader_test.go
+++ b/internal/storage/v1/elasticsearch/spanstore/reader_test.go
@@ -631,6 +631,7 @@ func testGet(typ string, t *testing.T) {
 			searchResult: &elastic.SearchResult{Aggregations: elastic.Aggregations(goodAggregations)},
 			expectedOutput: map[string]any{
 				operationsAggregation: []dbmodel.Operation{{Name: "123"}},
+				traceIDAggregation:    []dbmodel.TraceID{"123"},
 				"default":             []string{"123"},
 			},
 			expectedError: func() string {
@@ -685,7 +686,7 @@ func returnSearchFunc(typ string, r *spanReaderTest) (any, error) {
 			dbmodel.OperationQueryParameters{ServiceName: "someService"},
 		)
 	case traceIDAggregation:
-		return r.reader.findTraceIDs(context.Background(), &spanstore.TraceQueryParameters{})
+		return r.reader.findTraceIDs(context.Background(), &dbmodel.TraceQueryParameters{})
 	}
 	return nil, errors.New("Specify services, operations, traceIDs only")
 }
@@ -697,7 +698,7 @@ func TestSpanReader_bucketToStringArray(t *testing.T) {
 		buckets[1] = &elastic.AggregationBucketKeyItem{Key: "world"}
 		buckets[2] = &elastic.AggregationBucketKeyItem{Key: "2"}
 
-		actual, err := bucketToStringArray(buckets)
+		actual, err := bucketToStringArray[string](buckets)
 		require.NoError(t, err)
 
 		assert.EqualValues(t, []string{"hello", "world", "2"}, actual)
@@ -711,7 +712,7 @@ func TestSpanReader_bucketToStringArrayError(t *testing.T) {
 		buckets[1] = &elastic.AggregationBucketKeyItem{Key: "world"}
 		buckets[2] = &elastic.AggregationBucketKeyItem{Key: 2}
 
-		_, err := bucketToStringArray(buckets)
+		_, err := bucketToStringArray[string](buckets)
 		require.EqualError(t, err, "non-string key found in aggregation")
 	})
 }
@@ -740,7 +741,7 @@ func TestSpanReader_FindTraces(t *testing.T) {
 				},
 			}, nil)
 
-		traceQuery := &spanstore.TraceQueryParameters{
+		traceQuery := &dbmodel.TraceQueryParameters{
 			ServiceName: serviceName,
 			Tags: map[string]string{
 				"hello": "world",
@@ -786,7 +787,7 @@ func TestSpanReader_FindTracesInvalidQuery(t *testing.T) {
 				},
 			}, nil)
 
-		traceQuery := &spanstore.TraceQueryParameters{
+		traceQuery := &dbmodel.TraceQueryParameters{
 			ServiceName: "",
 			Tags: map[string]string{
 				"hello": "world",
@@ -819,7 +820,7 @@ func TestSpanReader_FindTracesAggregationFailure(t *testing.T) {
 				Responses: []*elastic.SearchResult{},
 			}, nil)
 
-		traceQuery := &spanstore.TraceQueryParameters{
+		traceQuery := &dbmodel.TraceQueryParameters{
 			ServiceName: serviceName,
 			Tags: map[string]string{
 				"hello": "world",
@@ -854,7 +855,7 @@ func TestSpanReader_FindTracesNoTraceIDs(t *testing.T) {
 				Responses: []*elastic.SearchResult{},
 			}, nil)
 
-		traceQuery := &spanstore.TraceQueryParameters{
+		traceQuery := &dbmodel.TraceQueryParameters{
 			ServiceName: serviceName,
 			Tags: map[string]string{
 				"hello": "world",
@@ -888,7 +889,7 @@ func TestSpanReader_FindTracesReadTraceFailure(t *testing.T) {
 		mockMultiSearchService(r).
 			Return(nil, errors.New("read error"))
 
-		traceQuery := &spanstore.TraceQueryParameters{
+		traceQuery := &dbmodel.TraceQueryParameters{
 			ServiceName: serviceName,
 			Tags: map[string]string{
 				"hello": "world",
@@ -927,7 +928,7 @@ func TestSpanReader_FindTracesSpanCollectionFailure(t *testing.T) {
 				},
 			}, nil)
 
-		traceQuery := &spanstore.TraceQueryParameters{
+		traceQuery := &dbmodel.TraceQueryParameters{
 			ServiceName: serviceName,
 			Tags: map[string]string{
 				"hello": "world",
@@ -959,12 +960,12 @@ func TestFindTraceIDs(t *testing.T) {
 }
 
 func TestTraceIDsStringsToModelsConversion(t *testing.T) {
-	traceIDs, err := convertTraceIDsStringsToModels([]string{"1", "2", "3"})
+	traceIDs, err := toModelTraceIDs([]dbmodel.TraceID{"1", "2", "3"})
 	require.NoError(t, err)
 	assert.Len(t, traceIDs, 3)
 	assert.Equal(t, model.NewTraceID(0, 1), traceIDs[0])
 
-	traceIDs, err = convertTraceIDsStringsToModels([]string{"dsfjsdklfjdsofdfsdbfkgbgoaemlrksdfbsdofgerjl"})
+	traceIDs, err = toModelTraceIDs([]dbmodel.TraceID{"dsfjsdklfjdsofdfsdbfkgbgoaemlrksdfbsdofgerjl"})
 	require.EqualError(t, err, "making traceID from string 'dsfjsdklfjdsofdfsdbfkgbgoaemlrksdfbsdofgerjl' failed: TraceID cannot be longer than 32 hex characters: dsfjsdklfjdsofdfsdbfkgbgoaemlrksdfbsdofgerjl")
 	assert.Empty(t, traceIDs)
 }
@@ -1009,11 +1010,11 @@ func mockSearchService(r *spanReaderTest) *mock.Call {
 }
 
 func TestTraceQueryParameterValidation(t *testing.T) {
-	var malformedtqp *spanstore.TraceQueryParameters
+	var malformedtqp *dbmodel.TraceQueryParameters
 	err := validateQuery(malformedtqp)
 	require.EqualError(t, err, ErrMalformedRequestObject.Error())
 
-	tqp := &spanstore.TraceQueryParameters{
+	tqp := &dbmodel.TraceQueryParameters{
 		ServiceName: "",
 		Tags: map[string]string{
 			"hello": "world",
@@ -1071,7 +1072,7 @@ func TestSpanReader_buildTraceIDAggregation(t *testing.T) {
 
 func TestSpanReader_buildFindTraceIDsQuery(t *testing.T) {
 	withSpanReader(t, func(r *spanReaderTest) {
-		traceQuery := &spanstore.TraceQueryParameters{
+		traceQuery := &dbmodel.TraceQueryParameters{
 			DurationMin:   time.Second,
 			DurationMax:   time.Second * 2,
 			StartTimeMin:  time.Time{},
@@ -1232,7 +1233,7 @@ func TestSpanReader_GetEmptyIndex(t *testing.T) {
 				Responses: []*elastic.SearchResult{},
 			}, nil)
 
-		traceQuery := &spanstore.TraceQueryParameters{
+		traceQuery := &dbmodel.TraceQueryParameters{
 			ServiceName: serviceName,
 			Tags: map[string]string{
 				"hello": "world",
@@ -1281,10 +1282,10 @@ func TestSpanReader_ArchiveTraces(t *testing.T) {
 }
 
 func TestConvertTraceIDsStringsToModels(t *testing.T) {
-	ids, err := convertTraceIDsStringsToModels([]string{"1", "2", "01", "02", "001", "002"})
+	ids, err := toModelTraceIDs([]dbmodel.TraceID{"1", "2", "01", "02", "001", "002"})
 	require.NoError(t, err)
 	assert.Equal(t, []model.TraceID{model.NewTraceID(0, 1), model.NewTraceID(0, 2)}, ids)
-	_, err = convertTraceIDsStringsToModels([]string{"1", "2", "01", "02", "001", "002", "blah"})
+	_, err = toModelTraceIDs([]dbmodel.TraceID{"1", "2", "01", "02", "001", "002", "blah"})
 	require.Error(t, err)
 }
 
diff --git a/internal/storage/v1/elasticsearch/spanstore/readerv1_test.go b/internal/storage/v1/elasticsearch/spanstore/readerv1_test.go
index 5e1b8e3c..5b68062a 100644
--- a/internal/storage/v1/elasticsearch/spanstore/readerv1_test.go
+++ b/internal/storage/v1/elasticsearch/spanstore/readerv1_test.go
@@ -49,7 +49,7 @@ func TestSpanReaderV1_FindTraces(t *testing.T) {
 		trace1 := getTestingTrace("service-1")
 		trace2 := getTestingTrace("service-2")
 		traces := []*model.Trace{trace1, trace2}
-		m.On("FindTraces", mock.Anything, mock.AnythingOfType("*spanstore.TraceQueryParameters")).Return(traces, nil)
+		m.On("FindTraces", mock.Anything, mock.AnythingOfType("*dbmodel.TraceQueryParameters")).Return(traces, nil)
 		actual, err := r.FindTraces(context.Background(), &spanstore.TraceQueryParameters{})
 		require.NoError(t, err)
 		assert.Equal(t, traces, actual)
@@ -58,16 +58,49 @@ func TestSpanReaderV1_FindTraces(t *testing.T) {
 
 func TestSpanReaderV1_FindTraceIDs(t *testing.T) {
 	withSpanReaderV1(func(r *SpanReaderV1, m *mocks.CoreSpanReader) {
-		traceId1 := model.NewTraceID(0, 1)
-		traceId2 := model.NewTraceID(0, 2)
-		traceIds := []model.TraceID{traceId1, traceId2}
-		m.On("FindTraceIDs", mock.Anything, mock.AnythingOfType("*spanstore.TraceQueryParameters")).Return(traceIds, nil)
+		traceId1Model := model.NewTraceID(0, 1)
+		traceId2Model := model.NewTraceID(0, 2)
+		traceId1 := dbmodel.TraceID(traceId1Model.String())
+		traceId2 := dbmodel.TraceID(traceId2Model.String())
+		traceIds := []dbmodel.TraceID{traceId1, traceId2}
+		m.On("FindTraceIDs", mock.Anything, mock.AnythingOfType("*dbmodel.TraceQueryParameters")).Return(traceIds, nil)
 		actual, err := r.FindTraceIDs(context.Background(), &spanstore.TraceQueryParameters{})
 		require.NoError(t, err)
-		assert.Equal(t, traceIds, actual)
+		expected := []model.TraceID{traceId1Model, traceId2Model}
+		assert.Equal(t, expected, actual)
 	})
 }
 
+func TestSpanReaderV1_FindTraceIDs_Errors(t *testing.T) {
+	tests := []struct {
+		name              string
+		returningTraceIDs []dbmodel.TraceID
+		returningErr      error
+		expectedError     string
+	}{
+		{
+			name:          "error from core span reader",
+			returningErr:  errors.New("error from core span reader"),
+			expectedError: "error from core span reader",
+		},
+		{
+			name:              "error from conversion",
+			returningTraceIDs: []dbmodel.TraceID{dbmodel.TraceID("wrong-id")},
+			expectedError:     "making traceID from string 'wrong-id' failed: strconv.ParseUint: parsing \"wrong-id\": invalid syntax",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			withSpanReaderV1(func(r *SpanReaderV1, m *mocks.CoreSpanReader) {
+				m.On("FindTraceIDs", mock.Anything, mock.AnythingOfType("*dbmodel.TraceQueryParameters")).Return(tt.returningTraceIDs, tt.returningErr)
+				actual, err := r.FindTraceIDs(context.Background(), &spanstore.TraceQueryParameters{})
+				assert.Nil(t, actual)
+				assert.ErrorContains(t, err, tt.expectedError)
+			})
+		})
+	}
+}
+
 func TestSpanReaderV1_GetServices(t *testing.T) {
 	withSpanReaderV1(func(r *SpanReaderV1, m *mocks.CoreSpanReader) {
 		services := []string{"service-1", "service-2"}