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
- Verify both timestamps use the same unit (epoch nanos for V3) and fix conversions
- Clamp or reject in the reader when endTime < startTime instead of letting it propagate
- Check clock sources: use one clock or apply known skew corrections
- 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
- Use one time unit (epoch nanos for V3) everywhere
- Apply clock-skew correction when timestamps come from multiple hosts
- Sanity-check intervals at deserialization time
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
- absolute start/end time is only supported for TRACE_V3 spans
- annotationKey name must not be empty
- Either tagGroupList or fieldNameList must have a size of…
- eventIdentifier cannot be less than 0
- invalid operator - not found left operand. operator=
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)