ruby-concurrency/concurrent-ruby · error · ArgumentError

`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE

Error message

`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}

What it means

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.

Source

Thrown at lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb:119

      # @!macro thread_pool_executor_method_prune_pool
      def prune_pool
        deprecated "#prune_pool has no effect and will be removed in the next release."
      end

      private

      def ns_initialize(opts)
        min_length       = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i
        max_length       = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i
        idletime         = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i
        @max_queue       = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i
        @synchronous     = opts.fetch(:synchronous, DEFAULT_SYNCHRONOUS)
        @fallback_policy = opts.fetch(:fallback_policy, :abort)

        raise ArgumentError.new("`synchronous` cannot be set unless `max_queue` is 0") if @synchronous && @max_queue > 0
        raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if max_length < DEFAULT_MIN_POOL_SIZE
        raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if max_length > DEFAULT_MAX_POOL_SIZE
        raise ArgumentError.new("`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if min_length < DEFAULT_MIN_POOL_SIZE
        raise ArgumentError.new("`min_threads` cannot be more than `max_threads`") if min_length > max_length
        raise ArgumentError.new("#{fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICY_CLASSES.include?(@fallback_policy)

        if @max_queue == 0
          if @synchronous
            queue = java.util.concurrent.SynchronousQueue.new
          else
            queue = java.util.concurrent.LinkedBlockingQueue.new
          end
        else
          queue = java.util.concurrent.LinkedBlockingQueue.new(@max_queue)
        end

        @executor = java.util.concurrent.ThreadPoolExecutor.new(
            min_length,
            max_length,
            idletime,

View on GitHub (pinned to 0b88d5ff75)

Solutions

  1. Omit max_threads: the default is already 2_147_483_647 (effectively unbounded)
  2. Clamp: max_threads = [wanted, 2_147_483_647].min
  3. For unbounded growth prefer Concurrent::CachedThreadPool or the global executors

Example fix

# before
Concurrent::ThreadPoolExecutor.new(max_threads: 2**32)
# after
Concurrent::ThreadPoolExecutor.new(max_threads: 2_147_483_647)
Defensive patterns

Strategy: validation

Validate before calling

MAX = Concurrent::ThreadPoolExecutor::DEFAULT_MAX_POOL_SIZE # 2147483647
max_threads = [Integer(cfg.fetch(:max_threads, MAX)), MAX].min
Concurrent::ThreadPoolExecutor.new(max_threads: max_threads)

Type guard

def valid_thread_count?(v, min = 0, max = 2_147_483_647)
  v.is_a?(Numeric) && v.to_i.between?(min, max)
end

Try / catch

begin
  Concurrent::ThreadPoolExecutor.new(max_threads: n)
rescue ArgumentError => e
  raise unless e.message.start_with?('`max_threads` cannot be greater than')
  Concurrent::ThreadPoolExecutor.new # default cap already max
end

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21). Data as JSON: /api/errors/4a8a46a3e34bec67. Report an issue: GitHub.