{"record":{"id":"63479636cbbc258a","repo":"t8y2/dbx","slug":"agent-runtime-thread-limits-must-be-positive","errorCode":null,"errorMessage":"Agent runtime thread limits must be positive","messagePattern":"Agent runtime thread limits must be positive","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"agents/common/src/main/java/com/dbx/agent/MultiSessionJsonRpcServer.java","lineNumber":359,"sourceCode":"    private static JsonObject errorResponse(JsonElement id, Throwable error) {\n        JsonObject response = new JsonObject();\n        response.addProperty(\"jsonrpc\", \"2.0\");\n        response.add(\"id\", id);\n        response.add(\"error\", AgentRpcError.toJson(error, \"request\", null));\n        return response;\n    }\n\n    private static String stringOrNull(JsonObject params, String key) {\n        return params.has(key) && !params.get(key).isJsonNull() ? params.get(key).getAsString() : null;\n    }\n\n    static final class RuntimeLimits {\n        private final int maximumRequestThreads;\n        private final int maximumCleanupThreads;\n\n        RuntimeLimits(int maximumRequestThreads, int maximumCleanupThreads) {\n            if (maximumRequestThreads <= 0 || maximumCleanupThreads <= 0) {\n                throw new IllegalArgumentException(\"Agent runtime thread limits must be positive\");\n            }\n            this.maximumRequestThreads = maximumRequestThreads;\n            this.maximumCleanupThreads = maximumCleanupThreads;\n        }\n\n        private static RuntimeLimits defaults() {\n            return new RuntimeLimits(MAX_REQUEST_THREADS, MAX_CLEANUP_THREADS);\n        }\n    }\n\n    private static String requiredSessionId(JsonObject params) {\n        if (!params.has(\"agentSessionId\") || params.get(\"agentSessionId\").getAsString().trim().isEmpty()) {\n            throw new IllegalArgumentException(\"agentSessionId is required\");\n        }\n        return params.get(\"agentSessionId\").getAsString();\n    }\n\n    private void writeResponse(JsonObject response) {","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/common/src/main/java/com/dbx/agent/MultiSessionJsonRpcServer.java#L341-L377","documentation":"The RuntimeLimits constructor validates its thread-pool bounds and throws IllegalArgumentException if either maximumRequestThreads or maximumCleanupThreads is <= 0. It is a fail-fast guard ensuring the server always configures positive thread limits for its executor pools.","triggerScenarios":"Constructing MultiSessionJsonRpcServer (or RuntimeLimits directly) with 0 or negative values, typically from misread config properties, integer-parse fallbacks, or constants defined as 0.","commonSituations":"Config file with 'threads=0' or a negative override; parsing empty strings to 0 and passing them through; unit tests probing validation; copy-paste errors in constant definitions.","solutions":["Pass positive values for both limits (use RuntimeLimits defaults if unsure)","Validate config values before constructing and fall back to defaults on invalid input","Fix the configuration source so thread-count properties are positive integers","Add a startup assertion/log when config-derived values are non-positive"],"exampleFix":"// before\nint threads = Integer.parseInt(cfg.get(\"requestThreads\")); // 0 on missing\nnew MultiSessionJsonRpcServer(agent, threads, threads);\n// after\nint threads = Math.max(1, Integer.parseInt(cfg.getOrDefault(\"requestThreads\", \"8\")));\nnew MultiSessionJsonRpcServer(agent, threads, Math.max(1, cleanupThreads));","handlingStrategy":"validation","validationCode":"int req = parsePositive(cfg, \"requestThreads\", 8);\nint cleanup = parsePositive(cfg, \"cleanupThreads\", 2);\n// parsePositive throws/defaults when value <= 0\nnew MultiSessionJsonRpcServer(agent, req, cleanup);","typeGuard":"boolean validLimits(int req, int cleanup) { return req > 0 && cleanup > 0; }","tryCatchPattern":"try {\n    limits = new RuntimeLimits(reqThreads, cleanupThreads);\n} catch (IllegalArgumentException e) {\n    limits = RuntimeLimits.defaults(); // fall back to built-in positive defaults\n}","preventionTips":["Clamp parsed config values with Math.max(1, value)","Use the defaults factory when config is absent or invalid","Fail at config-load time with a clear message, not deep in the constructor","Cover thread-limit parsing with unit tests including 0 and negatives"],"tags":["configuration","threading","illegal-argument","validation"],"backgroundTag":"invalid-configuration-value","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}