pinpoint-apm/pinpoint · error · IllegalArgumentException

span end time must be greater than or equal to start time

Error message

span end time must be greater than or equal to start time

What it means

V3 spans store absolute start and end times, so setTraceTime enforces the invariant endTime >= startTime and throws IllegalArgumentException on violation. A negative interval means corrupt, reordered, or unit-mismatched timestamps.

Solutions

  1. Verify both timestamps use the same unit (epoch nanos for V3) and fix conversions
  2. Clamp or reject in the reader when endTime < startTime instead of letting it propagate
  3. Check clock sources: use one clock or apply known skew corrections
  4. Log both raw values with units at the call site to diagnose unit/skew issues

Example fix

// before
long end = System.currentTimeMillis(); // millis, smaller than nano start
span.setTraceTime(SpanVersion.TRACE_V3, startNanos, end, elapsed); // throws
// after
long end = TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis());
if (end < startNanos) { end = startNanos; }
span.setTraceTime(SpanVersion.TRACE_V3, startNanos, end, elapsed);
Defensive patterns

Strategy: validation

Validate before calling

if (endTime < startTime) { log.warn("end {} before start {}", endTime, startTime); endTime = startTime; }

Type guard

boolean isConsistentInterval(long start, long end) { return end >= start; }

Try / catch

try { span.setTraceTime(version, start, end, elapsed); } catch (IllegalArgumentException e) { log.warn("invalid interval {}..{}: {}", start, end, e.getMessage()); }

Prevention

When it happens

Trigger: Calling setTraceTime(version, startTime, endTime, elapsedMillis) with endTime < startTime — typically from mixing millis and nanos, clocks skew across hops, or truncated timestamp bytes.

Common situations: Unit confusion (epoch millis passed as nanos), timestamps sourced from different machines without clock sync, corrupted HBase values, or off-by-one byte reads.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/7d986e0d6c22a55d. Report an issue: GitHub.

Appendix: source

Thrown at commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/SpanBo.java:207

        setVersion(version);
        this.startTime = startTime;
        this.elapsed = elapsedMillis;
        this.endTime = DEFAULT_END_TIME;
    }

    /**
     * Sets absolute span time for TRACE_V3 data.
     * startTime/endTime are epoch nanos. elapsedMillis is retained as the compatibility duration.
     */
    public void setTraceTime(int version, long startTime, long endTime, int elapsedMillis) {
        if (version != SpanVersion.TRACE_V3) {
            throw new IllegalArgumentException("absolute start/end time is only supported for TRACE_V3 spans");
        }
        if (endTime == DEFAULT_END_TIME) {
            throw new IllegalArgumentException("TRACE_V3 span end time is required");
        }
        if (endTime < startTime) {
            throw new IllegalArgumentException("span end time must be greater than or equal to start time");
        }

        setVersion(version);
        this.startTime = startTime;
        this.elapsed = elapsedMillis;
        this.endTime = endTime;
    }

    public boolean hasEndTime() {
        return endTime != DEFAULT_END_TIME;
    }

    public long getEndTimeMillis() {
        if (hasEndTime()) {
            return timeAccessor().toMillis(endTime);
        }
        return getStartTimeMillis() + elapsed;
    }

View on GitHub (pinned to 744c3d3075)