openzipkin/zipkin · error · IllegalArgumentException
rate should be between 0 and 1: was {}
Error message
rate should be between 0 and 1: was {} What it means
CollectorSampler.create(float) validates the sample rate is within [0,1]; outside that range it throws IllegalArgumentException with the offending value in the message. The rate is converted to a boundary on Long.MAX_VALUE for trace-id-based sampling, so values like 1.5 or a percentage like 10 (meaning 10%) are rejected.
Source
Thrown at zipkin-collector/core/src/main/java/zipkin2/collector/CollectorSampler.java:34
*
* <p>Accepts a percentage of trace ids by comparing their absolute value against a potentially
* dynamic boundary. eg {@code isSampled == abs(traceId) <= boundary}
*
* <p>While idempotent, this implementation's sample rate won't exactly match the input rate because
* trace ids are not perfectly distributed across 64bits. For example, tests have shown an error
* rate of 3% when 100K trace ids are {@link java.util.Random#nextLong random}.
*/
public abstract class CollectorSampler {
public static final CollectorSampler ALWAYS_SAMPLE = CollectorSampler.create(1.0f);
/**
* Returns a trace ID sampler with the indicated rate.
*
* @param rate minimum sample rate is 0.0001, or 0.01% of traces
*/
public static CollectorSampler create(float rate) {
if (rate < 0 || rate > 1)
throw new IllegalArgumentException("rate should be between 0 and 1: was " + rate);
final long boundary = (long) (Long.MAX_VALUE * rate); // safe cast as less <= 1
return new CollectorSampler() {
@Override
protected long boundary() {
return boundary;
}
};
}
protected abstract long boundary();
/**
* Returns true if spans with this trace ID should be recorded to storage.
*
* <p>Zipkin v1 allows storage-layer sampling, which can help prevent spikes in traffic from
* overloading the system. Debug spans are always stored.
*
* <p>This uses only the lower 64 bits of the trace ID as instrumentation still send mixed traceView on GitHub (pinned to 878ce2a1fa)
Solutions
- Express the rate as a fraction in [0,1]: 10% sampling → 0.1f.
- If your config is a percentage, divide by 100 before calling create.
- Treat 'unset' sentinels (-1) by falling back to ALWAYS_SAMPLE or a documented default instead of forwarding them.
Example fix
// before
float rate = Float.parseFloat(env.get("COLLECTOR_SAMPLE_PERCENTAGE")); // e.g. "10"
CollectorSampler.create(rate); // throws 'rate should be between 0 and 1: was 10.0'
// after
float pct = Float.parseFloat(env.get("COLLECTOR_SAMPLE_PERCENTAGE"));
CollectorSampler.create(pct / 100.0f); // 10 -> 0.1 Defensive patterns
Strategy: validation
Validate before calling
java
float rate = Float.parseFloat(pct) / 100f;
if (rate < 0f || rate > 1f) throw new IllegalArgumentException("sample rate must be 0-100%: " + pct);
return CollectorSampler.create(rate); Prevention
- Document config values as percentages but convert to fractions before create().
- Never forward sentinel values like -1 to the sampler.
When it happens
Trigger: Calling CollectorSampler.create(rate) with rate < 0 or > 1 — the classic case is passing a percentage (e.g. 10 for 10%, or 0.1 for 0.1%) instead of a fraction (0.1 for 10%).
Common situations: Env var COLLECTOR_SAMPLE_PERCENTAGE=10 piped straight into create(); confusion between basis points, percent, and probability; a default of -1 used as 'unset' sentinel reaching the sampler.
Related errors
AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14).
Data as JSON: /api/errors/40e82538a95e4b6f.
Report an issue: GitHub.