{"record":{"id":"304d22415d2864e5","repo":"opendataloader-project/opendataloader-pdf","slug":"timeout-must-be-non-negative-s","errorCode":null,"errorMessage":"Timeout must be non-negative: %s","messagePattern":"Timeout must be non-negative: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HybridConfig.java","lineNumber":121,"sourceCode":"\n    /**\n     * Gets the request timeout in milliseconds.\n     *\n     * @return The timeout in milliseconds.\n     */\n    public int getTimeoutMs() {\n        return timeoutMs;\n    }\n\n    /**\n     * Sets the request timeout in milliseconds. Use 0 for no timeout.\n     *\n     * @param timeoutMs The timeout in milliseconds (0 = no timeout).\n     * @throws IllegalArgumentException if timeout is negative.\n     */\n    public void setTimeoutMs(int timeoutMs) {\n        if (timeoutMs < 0) {\n            throw new IllegalArgumentException(\"Timeout must be non-negative: \" + timeoutMs);\n        }\n        this.timeoutMs = timeoutMs;\n    }\n\n    /**\n     * Checks if fallback to Java processing is enabled when backend fails.\n     *\n     * @return true if fallback is enabled, false otherwise.\n     */\n    public boolean isFallbackToJava() {\n        return fallbackToJava;\n    }\n\n    /**\n     * Sets whether to fallback to Java processing when backend fails.\n     *\n     * @param fallbackToJava true to enable fallback, false to fail on backend error.\n     */","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/opendataloader-project/opendataloader-pdf/blob/a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8/java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HybridConfig.java#L103-L139","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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))`."],"exampleFix":"// before: computed timeout can go negative\nconfig.setTimeoutMs(targetMs - elapsedMs);\n\n// after: clamp to minimum of 0\nconfig.setTimeoutMs(Math.max(0, targetMs - elapsedMs));","handlingStrategy":"validation","validationCode":"int timeout = parseTimeout(configSource); // from CLI, config file, or env\nif (timeout < 0) {\n    throw new IllegalArgumentException(\n        \"Timeout must be >= 0 (0 = no timeout). Got: \" + timeout);\n}\nconfig.setTimeoutMs(timeout);","typeGuard":"public static boolean isValidTimeout(int timeoutMs) {\n    return timeoutMs >= 0;\n}","tryCatchPattern":"try {\n    config.setTimeoutMs(requestedTimeout);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Timeout must be non-negative\")) {\n        // Clamp to 0 (no timeout) rather than failing\n        config.setTimeoutMs(0);\n        LOGGER.warning(\"Negative timeout clamped to 0 (no timeout)\");\n    } else {\n        throw e;\n    }\n}","preventionTips":["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."],"tags":["configuration","validation","hybrid","timeout","programming-error"],"backgroundTag":null,"analyzedSha":"a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8","analyzedAt":"2026-08-14T05:22:03.953Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}