{"record":{"id":"4a8a46a3e34bec67","repo":"ruby-concurrency/concurrent-ruby","slug":"max-threads-cannot-be-greater-than-default-max","errorCode":null,"errorMessage":"`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}","messagePattern":"`max_threads` cannot be greater than #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb","lineNumber":119,"sourceCode":"\n      # @!macro thread_pool_executor_method_prune_pool\n      def prune_pool\n        deprecated \"#prune_pool has no effect and will be removed in the next release.\"\n      end\n\n      private\n\n      def ns_initialize(opts)\n        min_length       = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i\n        max_length       = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i\n        idletime         = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i\n        @max_queue       = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i\n        @synchronous     = opts.fetch(:synchronous, DEFAULT_SYNCHRONOUS)\n        @fallback_policy = opts.fetch(:fallback_policy, :abort)\n\n        raise ArgumentError.new(\"`synchronous` cannot be set unless `max_queue` is 0\") if @synchronous && @max_queue > 0\n        raise ArgumentError.new(\"`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}\") if max_length < DEFAULT_MIN_POOL_SIZE\n        raise ArgumentError.new(\"`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}\") if max_length > DEFAULT_MAX_POOL_SIZE\n        raise ArgumentError.new(\"`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}\") if min_length < DEFAULT_MIN_POOL_SIZE\n        raise ArgumentError.new(\"`min_threads` cannot be more than `max_threads`\") if min_length > max_length\n        raise ArgumentError.new(\"#{fallback_policy} is not a valid fallback policy\") unless FALLBACK_POLICY_CLASSES.include?(@fallback_policy)\n\n        if @max_queue == 0\n          if @synchronous\n            queue = java.util.concurrent.SynchronousQueue.new\n          else\n            queue = java.util.concurrent.LinkedBlockingQueue.new\n          end\n        else\n          queue = java.util.concurrent.LinkedBlockingQueue.new(@max_queue)\n        end\n\n        @executor = java.util.concurrent.ThreadPoolExecutor.new(\n            min_length,\n            max_length,\n            idletime,","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb#L101-L137","documentation":"On JRuby, ThreadPoolExecutor caps max_threads at DEFAULT_MAX_POOL_SIZE = java.lang.Integer::MAX_VALUE (2_147_483_647) because the underlying java.util.concurrent.ThreadPoolExecutor takes an int. ns_initialize raises ArgumentError when the coerced value exceeds it. Values are coerced with to_i first, so oversized floats like 3e9 become 3000000000 and trip this check.","triggerScenarios":"max_threads: 2**31 or any integer above 2147483647 on JRuby; max_threads: 3_000_000_000.0 (to_i gives 3000000000); generated or copy-pasted config with absurd thread counts.","commonSituations":"Passing a huge number to mean 'effectively unbounded'; generated configuration templates multiplying ENV values; porting config from systems without an int cap. Note Float::INFINITY.to_i raises FloatDomainError, a different error, before this check is reached.","solutions":["Omit max_threads: the default is already 2_147_483_647 (effectively unbounded)","Clamp: max_threads = [wanted, 2_147_483_647].min","For unbounded growth prefer Concurrent::CachedThreadPool or the global executors"],"exampleFix":"# before\nConcurrent::ThreadPoolExecutor.new(max_threads: 2**32)\n# after\nConcurrent::ThreadPoolExecutor.new(max_threads: 2_147_483_647)","handlingStrategy":"validation","validationCode":"MAX = Concurrent::ThreadPoolExecutor::DEFAULT_MAX_POOL_SIZE # 2147483647\nmax_threads = [Integer(cfg.fetch(:max_threads, MAX)), MAX].min\nConcurrent::ThreadPoolExecutor.new(max_threads: max_threads)","typeGuard":"def valid_thread_count?(v, min = 0, max = 2_147_483_647)\n  v.is_a?(Numeric) && v.to_i.between?(min, max)\nend","tryCatchPattern":"begin\n  Concurrent::ThreadPoolExecutor.new(max_threads: n)\nrescue ArgumentError => e\n  raise unless e.message.start_with?('`max_threads` cannot be greater than')\n  Concurrent::ThreadPoolExecutor.new # default cap already max\nend","preventionTips":["Omit max_threads when 'unbounded' is intended: the default is already the cap","Never pass Float::INFINITY for thread counts (FloatDomainError instead)","Clamp generated config: [wanted, 2_147_483_647].min"],"tags":["ruby","jruby","concurrency","thread-pool","argument-error","configuration","integer-overflow"],"backgroundTag":"invalid-thread-pool-configuration","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}