opendataloader-project/opendataloader-pdf · error · IllegalArgumentException
Timeout must be non-negative: %s
Error message
Timeout must be non-negative: %s
What it means
HybridConfig.setTimeoutMs() rejects any value below zero. A timeout of 0 means 'no timeout' (infinite wait), which is the default (DEFAULT_TIMEOUT_MS = 0). Negative timeouts are nonsensical for OkHttp's timeout configuration and would cause undefined behavior in the underlying HTTP client, so they are rejected eagerly with the offending value in the message.
Source
Thrown at java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HybridConfig.java:121
/**
* Gets the request timeout in milliseconds.
*
* @return The timeout in milliseconds.
*/
public int getTimeoutMs() {
return timeoutMs;
}
/**
* Sets the request timeout in milliseconds. Use 0 for no timeout.
*
* @param timeoutMs The timeout in milliseconds (0 = no timeout).
* @throws IllegalArgumentException if timeout is negative.
*/
public void setTimeoutMs(int timeoutMs) {
if (timeoutMs < 0) {
throw new IllegalArgumentException("Timeout must be non-negative: " + timeoutMs);
}
this.timeoutMs = timeoutMs;
}
/**
* Checks if fallback to Java processing is enabled when backend fails.
*
* @return true if fallback is enabled, false otherwise.
*/
public boolean isFallbackToJava() {
return fallbackToJava;
}
/**
* Sets whether to fallback to Java processing when backend fails.
*
* @param fallbackToJava true to enable fallback, false to fail on backend error.
*/View on GitHub (pinned to a7789b8e77)
Solutions
- Use 0 for no timeout (infinite wait), or any positive integer for a specific millisecond timeout.
- Validate the input before calling setTimeoutMs: `if (timeout < 0) throw new IllegalArgumentException(...)`.
- Check the CLI argument or config file for a stray negative sign.
- If the timeout is computed dynamically, clamp it: `setTimeoutMs(Math.max(0, computedTimeout))`.
Example fix
// before: computed timeout can go negative config.setTimeoutMs(targetMs - elapsedMs); // after: clamp to minimum of 0 config.setTimeoutMs(Math.max(0, targetMs - elapsedMs));
Defensive patterns
Strategy: validation
Validate before calling
int timeout = parseTimeout(configSource); // from CLI, config file, or env
if (timeout < 0) {
throw new IllegalArgumentException(
"Timeout must be >= 0 (0 = no timeout). Got: " + timeout);
}
config.setTimeoutMs(timeout); Type guard
public static boolean isValidTimeout(int timeoutMs) {
return timeoutMs >= 0;
} Try / catch
try {
config.setTimeoutMs(requestedTimeout);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Timeout must be non-negative")) {
// Clamp to 0 (no timeout) rather than failing
config.setTimeoutMs(0);
LOGGER.warning("Negative timeout clamped to 0 (no timeout)");
} else {
throw e;
}
} Prevention
- Validate timeout values at the CLI parser or config loader boundary.
- Use Math.max(0, computedValue) when computing timeouts dynamically.
- Remember: 0 means no timeout (infinite wait), not 'fail immediately'.
- Set explicit timeouts in production to avoid hanging on unreachable servers.
When it happens
Trigger: Calling config.setTimeoutMs(-1) or any negative integer. This can originate from a CLI parsing error (e.g., --hybrid-timeout -1), arithmetic underflow in a config builder, or a misconfigured properties file where the timeout is computed as a difference that goes negative.
Common situations: CLI argument `--hybrid-timeout -500` (user error or script bug); timeout calculated as (someBaseline - someOffset) where offset exceeds baseline; reading from a YAML/JSON config where the value is accidentally negative; environment variable parsed as integer but containing a negative number.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Hybrid backend type cannot be null or empty
- Unknown hybrid backend: %s. Supported backends: %s
- Max concurrent requests must be positive: %s
- Unsupported hybrid backend '%s'. Supported values: %s
- Invalid regionlistStrategy: %s (expected table-first or list
AI-assisted analysis of opendataloader-project/opendataloader-pdf@a7789b8e77 (2026-08-14).
Data as JSON: /api/errors/304d22415d2864e5.
Report an issue: GitHub.