{"record":{"id":"9b7e814868495daf","repo":"opendataloader-project/opendataloader-pdf","slug":"max-concurrent-requests-must-be-positive-s","errorCode":null,"errorMessage":"Max concurrent requests must be positive: %s","messagePattern":"Max concurrent requests must be positive: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HybridConfig.java","lineNumber":161,"sourceCode":"\n    /**\n     * Gets the maximum number of concurrent requests to the backend.\n     *\n     * @return The maximum concurrent requests.\n     */\n    public int getMaxConcurrentRequests() {\n        return maxConcurrentRequests;\n    }\n\n    /**\n     * Sets the maximum number of concurrent requests to the backend.\n     *\n     * @param maxConcurrentRequests The maximum concurrent requests.\n     * @throws IllegalArgumentException if the value is not positive.\n     */\n    public void setMaxConcurrentRequests(int maxConcurrentRequests) {\n        if (maxConcurrentRequests <= 0) {\n            throw new IllegalArgumentException(\"Max concurrent requests must be positive: \" + maxConcurrentRequests);\n        }\n        this.maxConcurrentRequests = maxConcurrentRequests;\n    }\n\n    /**\n     * Gets the default URL for a given hybrid backend.\n     *\n     * @param hybrid The hybrid backend name (docling, docling-fast, hancom, azure, google).\n     * @return The default URL, or null if the backend requires explicit URL.\n     */\n    public static String getDefaultUrl(String hybrid) {\n        if (hybrid == null) {\n            return null;\n        }\n        String lowerHybrid = hybrid.toLowerCase();\n        // Both \"docling\" and \"docling-fast\" (deprecated) use the same server\n        if (\"docling\".equals(lowerHybrid) || \"docling-fast\".equals(lowerHybrid)) {\n            return DOCLING_FAST_DEFAULT_URL;","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/opendataloader-project/opendataloader-pdf/blob/a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8/java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HybridConfig.java#L143-L179","documentation":"HybridConfig.setMaxConcurrentRequests() rejects zero and negative values. The concurrency limit controls the Semaphore or thread pool size for parallel backend requests, and zero/negative concurrency is semantically invalid — it would mean no requests can ever execute. The default is DEFAULT_MAX_CONCURRENT_REQUESTS = 4.","triggerScenarios":"Calling config.setMaxConcurrentRequests(0) or any negative integer. This typically comes from a CLI argument `--hybrid-concurrency 0`, a config file with a zero value, or a dynamic computation that produces zero (e.g., availableProcessors() - someOffset on a single-core machine).","commonSituations":"CLI argument `--hybrid-max-requests 0` (user intended to disable limits but 0 means disabled-concurrency); computing concurrency from Runtime.getRuntime().availableProcessors() and subtracting cores on a constrained container; config file typo setting the value to 0 instead of omitting it.","solutions":["Set to at least 1 (sequential) or the default 4 for typical parallel processing.","If computing dynamically, clamp: `setMaxConcurrentRequests(Math.max(1, computed))`.","Use DEFAULT_MAX_CONCURRENT_REQUESTS constant if unsure.","Check CLI/config for accidental zero values."],"exampleFix":"// before: can produce 0 on single-core containers\nconfig.setMaxConcurrentRequests(Runtime.getRuntime().availableProcessors() - 1);\n\n// after: clamp to minimum 1\nconfig.setMaxConcurrentRequests(\n    Math.max(1, Runtime.getRuntime().availableProcessors() - 1));","handlingStrategy":"validation","validationCode":"int concurrency = parseConcurrency(configSource);\nif (concurrency <= 0) {\n    throw new IllegalArgumentException(\n        \"Max concurrent requests must be >= 1. Got: \" + concurrency);\n}\nconfig.setMaxConcurrentRequests(concurrency);","typeGuard":"public static boolean isValidConcurrency(int maxConcurrent) {\n    return maxConcurrent > 0;\n}","tryCatchPattern":"try {\n    config.setMaxConcurrentRequests(requestedConcurrency);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"must be positive\")) {\n        // Use default instead of failing\n        config.setMaxConcurrentRequests(HybridConfig.DEFAULT_MAX_CONCURRENT_REQUESTS);\n        LOGGER.warning(\"Invalid concurrency, using default: \"\n            + HybridConfig.DEFAULT_MAX_CONCURRENT_REQUESTS);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Validate concurrency values at the CLI parser or config boundary.","Use Math.max(1, computedValue) when deriving concurrency from system properties.","Remember: 0 does NOT mean 'unlimited' — it is invalid. Use a large positive number instead.","Default of 4 is reasonable for most backends; increase only if the server can handle more."],"tags":["configuration","validation","hybrid","concurrency","programming-error"],"backgroundTag":null,"analyzedSha":"a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8","analyzedAt":"2026-08-14T05:22:03.953Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}