didi/DoKit · error · IllegalArgumentException
The duration is less than 0.
Error message
The duration is less than 0.
What it means
The second guard in DebouncingUtils.isValid: the debounce window duration must be >= 0 because it is added to SystemClock.elapsedRealtime() to compute the expiry timestamp stored in KEY_MILLIS_MAP. A negative duration would create a timestamp in the past and break the 'validTime' semantics, so it is rejected up front.
Source
Thrown at Android/dokit-util/src/main/java/com/didichuxing/doraemonkit/util/DebouncingUtils.java:65
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isValid(@NonNull final View view, final long duration) {
return isValid(String.valueOf(view.hashCode()), duration);
}
/**
* Return whether the key is not in a jitter state.
*
* @param key The key.
* @param duration The duration.
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isValid(@NonNull String key, final long duration) {
if (TextUtils.isEmpty(key)) {
throw new IllegalArgumentException("The key is null.");
}
if (duration < 0) {
throw new IllegalArgumentException("The duration is less than 0.");
}
long curTime = SystemClock.elapsedRealtime();
clearIfNecessary(curTime);
Long validTime = KEY_MILLIS_MAP.get(key);
if (validTime == null || curTime >= validTime) {
KEY_MILLIS_MAP.put(key, curTime + duration);
return true;
}
return false;
}
private static void clearIfNecessary(long curTime) {
if (KEY_MILLIS_MAP.size() < CACHE_SIZE) return;
for (Iterator<Map.Entry<String, Long>> it = KEY_MILLIS_MAP.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, Long> entry = it.next();
Long validTime = entry.getValue();
if (curTime >= validTime) {
it.remove();View on GitHub (pinned to 626827cddb)
Solutions
- Pass 0 to make every call valid immediately (no debounce) instead of a negative value.
- Sanitize config values: duration = Math.max(0, configDuration).
- Validate parsed durations at load time and use an explicit sentinel/boolean rather than a negative number.
Example fix
// before
long d = remoteConfig.getLong("debounce_ms", -1);
DebouncingUtils.isValid(key, d); // throws when config missing
// after
long d = Math.max(0, remoteConfig.getLong("debounce_ms", 0));
DebouncingUtils.isValid(key, d); Defensive patterns
Strategy: validation
Validate before calling
long safeDuration = Math.max(0, duration); boolean valid = DebouncingUtils.isValid(key, safeDuration);
Prevention
- Use 0 (not -1) to disable debouncing.
- Validate remote-config durations at load time.
When it happens
Trigger: Passing a negative duration constant: isValid(key, -1); durations parsed from config (remote config, JSON) without validation; using -1 as a 'disable debounce' sentinel.
Common situations: Remote-config-driven debounce intervals that default to -1 when the key is missing; time-unit confusion (passing 500 ms as -500 after sign arithmetic); feature flags that try to express 'no debounce' with a negative number.
Related errors
- The key is null.
- maxStoredHeapDumps must be at least 1
- Index cannot be negative: " + index
- precision shouldn't be less than zero!
- byteSize shouldn't be less than zero!
AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14).
Data as JSON: /api/errors/e3da3f33d34fc6b9.
Report an issue: GitHub.