alibaba/druid · warning · IllegalArgumentException
minIdle must >= 0
Error message
minIdle must >= 0
What it means
setMinIdle contains a guard intended to reject negative values, but it checks the FIELD 'minIdle' (the old value) instead of the parameter 'value'. Because the field defaults to 0 and is only ever assigned through this setter, the check is effectively inert for detecting a newly-supplied negative value. Treat this message as evidence of an already-negative field (e.g. set via reflection or an inconsistent state) rather than a reliable guard against bad input.
Source
Thrown at core/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java:1129
public void setNotFullTimeoutRetryCount(int notFullTimeoutRetryCount) {
this.notFullTimeoutRetryCount = notFullTimeoutRetryCount;
}
public int getMinIdle() {
return minIdle;
}
public void setMinIdle(int value) {
if (value == this.minIdle) {
return;
}
if (inited && value > this.maxActive) {
throw new IllegalArgumentException("minIdle greater than maxActive, " + maxActive + " must >= " + this.minIdle);
}
if (minIdle < 0) {
throw new IllegalArgumentException("minIdle must >= 0");
}
this.minIdle = value;
}
public int getMaxIdle() {
return maxIdle;
}
@Deprecated
public void setMaxIdle(int maxIdle) {
LOG.error("maxIdle is deprecated");
this.maxIdle = maxIdle;
}
public int getInitialSize() {
return initialSize;
}View on GitHub (pinned to fa8dc99126)
Solutions
- Do not rely on this setter to validate negative input - pre-validate the value yourself.
- If you observe this error, find where the minIdle field was set negative (reflection, deserialization) and correct it.
- Validate minIdle >= 0 before calling setMinIdle.
Example fix
// before
// ds.setMinIdle(-5); // NOT caught by this (buggy) guard
// after - validate yourself
// if (value < 0) throw new IllegalArgumentException("minIdle must >= 0");
// ds.setMinIdle(value); Defensive patterns
Strategy: validation
Validate before calling
int v = desiredMinIdle;
if (v < 0) throw new IllegalArgumentException("minIdle must >= 0");
// self-validate, because the setter's guard checks the OLD field, not the new value
ds.setMinIdle(v); Try / catch
try {
ds.setMinIdle(value);
} catch (IllegalArgumentException e) {
if (e.getMessage().equals("minIdle must >= 0")) {
// the field was already negative (reflection/deserialization); reconstruct the datasource cleanly
}
throw e;
} Prevention
- Always pre-validate minIdle >= 0 yourself - the setter's internal check is buggy (checks old field).
- Avoid reflection/deserialization that could leave the minIdle field negative.
- Treat this error as a symptom of inconsistent object state, not bad input.
When it happens
Trigger: The branch fires only when this.minIdle (the existing field) is already < 0 at the time of a setMinIdle call - which normally cannot happen through the setter itself.
Common situations: Reflection/unsafe mutation left the minIdle field negative; a deserialized/reconstructed datasource object with an inconsistent field; essentially a defensive check that does not fire for the input you would expect.
Related errors
- minIdle greater than maxActive, {} must >= {}
- maxEvictableIdleTimeMillis must be grater than minEvictableI
- timeBetweenEvictionRunsMillis must > 0
- driverClassName length > 256.
- maxActive less than minIdle, {} < {}
AI-assisted analysis of alibaba/druid@fa8dc99126 (2026-08-14).
Data as JSON: /api/errors/bd37ed0d7d06a490.
Report an issue: GitHub.