jaegertracing/jaeger · error

%w: %w

Error message

%w: %w

What it means

validateQuery rejects trace queries that lack a service name by wrapping ErrServiceNameNotSet together with errors.ErrUnsupported (double %w, Go 1.20 multi-error wrapping). The Cassandra index is partitioned by service, so a service-less query cannot be executed — it would scan an empty partition and be indistinguishable from 'no traces found'.

Source

Thrown at internal/storage/v1/cassandra/spanstore/reader.go:227

	return spans, nil
}

// GetTrace takes a traceID and returns the spans associated with that traceID
func (s *SpanReader) GetTrace(ctx context.Context, traceID dbmodel.TraceID) ([]dbmodel.Span, error) {
	return s.readTrace(ctx, traceID)
}

func validateQuery(p *tracestore.TraceQueryParams) error {
	if p == nil {
		return ErrMalformedRequestObject
	}
	// Every index is keyed by service name, so a query without one has no partition to
	// read: queryByService would run with an empty partition key and return zero rows,
	// which is indistinguishable from "no matching traces". Refusing it says what is
	// actually true (RFC 0013 §3.3); the query service normally rejects such a query
	// first, from the capability this reader declares.
	if p.ServiceName == "" {
		return fmt.Errorf("%w: %w", ErrServiceNameNotSet, errors.ErrUnsupported)
	}
	if p.StartTimeMin.IsZero() || p.StartTimeMax.IsZero() {
		return ErrStartAndEndTimeNotSet
	}
	if !p.StartTimeMin.IsZero() && !p.StartTimeMax.IsZero() && p.StartTimeMax.Before(p.StartTimeMin) {
		return ErrStartTimeMinGreaterThanMax
	}
	if p.DurationMin != 0 && p.DurationMax != 0 && p.DurationMin > p.DurationMax {
		return ErrDurationMinGreaterThanMax
	}
	if (p.DurationMin != 0 || p.DurationMax != 0) && p.Attributes.Len() > 0 {
		return ErrDurationAndTagQueryNotSupported
	}
	return nil
}

// FindTraces retrieves traces that match the traceQuery
func (s *SpanReader) FindTraces(ctx context.Context, traceQuery *tracestore.TraceQueryParams) iter.Seq2[dbmodel.Trace, error] {

View on GitHub (pinned to 806f444784)

Solutions

  1. Set Query.ServiceName to a non-empty value before calling FindTraceIDs/FindTraces.
  2. Check errors.Is(err, ErrServiceNameNotSet) and errors.Is(err, errors.ErrUnsupported) to detect this case programmatically and prompt the user for a service.
  3. If you need service-less searches, use a backend/index that supports them (e.g. Elasticsearch/OpenSearch storage) rather than Cassandra.
  4. Update calling code to rely on the query service's capability check so the query is validated before reaching storage.

Example fix

// before
spans, err := reader.FindTraceIDs(ctx, tracestore.Query{StartTimeMin: t1, StartTimeMax: t2})
// after
spans, err := reader.FindTraceIDs(ctx, tracestore.Query{ServiceName: "frontend", StartTimeMin: t1, StartTimeMax: t2})
Defensive patterns

Strategy: validation

Validate before calling

if q.ServiceName == "" {
    return errors.New("Query.ServiceName is required for Cassandra trace queries")
}
if q.StartTimeMin.IsZero() || q.StartTimeMax.IsZero() {
    return errors.New("Query start/end times are required")
}
if q.StartTimeMax.Before(q.StartTimeMin) {
    return errors.New("StartTimeMax must not be before StartTimeMin")
}

Type guard

func isValidQuery(q tracestore.Query) bool {
    return q.ServiceName != "" && !q.StartTimeMin.IsZero() && !q.StartTimeMax.IsZero() && !q.StartTimeMax.Before(q.StartTimeMin)
}

Try / catch

ids, err := reader.FindTraceIDs(ctx, q)
if err != nil {
    if errors.Is(err, spanstore.ErrServiceNameNotSet) || errors.Is(err, errors2.ErrUnsupported) {
        // surface 'service name required' to the caller
    }
    return err
}

Prevention

When it happens

Trigger: Calling FindTraceIDs (or FindTraces) with tracestore.Query where ServiceName == ""; also asserted in TestTraceQueryParameterValidation. The query service normally blocks this earlier via declared capabilities, but direct storage clients hit it here.

Common situations: Custom tooling or tests invoking SpanReader.FindTraceIDs directly without filling Query.ServiceName; UI/API regressions that drop the service parameter; scripts built against other backends that allow global queries.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/a5da5613f4307bcd. Report an issue: GitHub.