openzipkin/zipkin · error · AssertionError

Don't use test data that results in indeterministic ordering

Error message

Don't use test data that results in indeterministic ordering:
l={}, r={}

What it means

ITStorage's span-sorting comparator throws AssertionError when two spans compare equal on every discriminator (same names, timestamps, and durations). The sharedSortWithTimestamp helper relies on test data having deterministic order; ties mean the assertion 'same span seen twice or ambiguous data' cannot be verified reliably, so the harness flags the test data itself as broken.

Source

Thrown at zipkin-tests/src/main/java/zipkin2/storage/ITStorage.java:234

      int traceId = l.traceId().compareTo(r.traceId());
      if (traceId != 0) return traceId;
      int id = l.id().compareTo(r.id());
      if (id != 0) return id;
      int shared = Boolean.compare(TRUE.equals(l.shared()), TRUE.equals(r.shared()));
      if (shared != 0) return shared;

      if (l.name() != null && r.name() != null) {
        int name = l.name().compareTo(r.name());
        if (name != 0) return name;
      }

      int timestamp = Long.compare(l.timestampAsLong(), r.timestampAsLong());
      if (timestamp != 0) return timestamp;

      int duration = Long.compare(l.durationAsLong(), r.durationAsLong());
      if (duration != 0) return duration;

      throw new AssertionError("Don't use test data that results in indeterministic ordering:\n" +
        "l=" + l + ", r=" + r);
    });
    return result;
  }
}

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Make test spans distinguishable: give each a distinct name, timestamp, or duration.
  2. De-duplicate the span list before sorting/asserting (the duplicate is usually the bug in the test).
  3. If you genuinely insert the same span twice, assert on counts separately instead of relying on the sorted comparison.

Example fix

// before: two spans with identical name/timestamp/duration
Span a = span.toBuilder().build();
Span b = span.toBuilder().build();

// after: vary the timestamp
Span a = span.toBuilder().build();
Span b = span.toBuilder().timestamp(span.timestampAsLong() + 1000).build();
Defensive patterns

Strategy: validation

Validate before calling

Set<String> seen = new HashSet<>();
for (Span s : spans) {
  String key = s.name() + ":" + s.timestampAsLong() + ":" + s.durationAsLong();
  if (!seen.add(key)) throw new AssertionError("duplicate span in test data: " + key);
}

Prevention

When it happens

Trigger: Calling the sort helper (used by assertSameTags/assertSpanCount style checks) with test traces containing two spans that share name, timestamp, duration, and have null-vs-null ordering fields — i.e. identical by every compared key.

Common situations: Custom integration tests that insert duplicate spans or reuse TestObjects spans without varying timestamps; batch-span-consumer tests that accept the same span twice; test data generators that zero out timestamps.

Related errors


AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14). Data as JSON: /api/errors/1f96403602b6c542. Report an issue: GitHub.