ruby-concurrency/concurrent-ruby · error · ArgumentError

cannot enqueue nil

Error message

cannot enqueue nil

What it means

This is the JRuby (java.util.PriorityQueue-backed) engine behind Concurrent::PriorityQueue. The heap uses nil as its sentinel for 'queue empty' (pop returns nil when nothing is dequeued), so a nil item would make a real entry indistinguishable from emptiness — push therefore rejects nil with ArgumentError.

Source

Thrown at lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb:69

          @queue.size
        end
        alias_method :size, :length

        # @!macro priority_queue_method_peek
        def peek
          @queue.peek
        end

        # @!macro priority_queue_method_pop
        def pop
          @queue.poll
        end
        alias_method :deq, :pop
        alias_method :shift, :pop

        # @!macro priority_queue_method_push
        def push(item)
          raise ArgumentError.new('cannot enqueue nil') if item.nil?
          @queue.add(item)
        end
        alias_method :<<, :push
        alias_method :enq, :push

        # @!macro priority_queue_method_from_list
        def self.from_list(list, opts = {})
          queue = new(opts)
          list.each{|item| queue << item }
          queue
        end
      end
    end
  end
end

View on GitHub (pinned to 0b88d5ff75)

Solutions

  1. Filter nils before enqueueing: `items.compact.each { |i| queue << i }`.
  2. Use fetch with an explicit default instead of nil-producing lookups: `queue << config.fetch(:retry_after, DEFAULT)`.
  3. Represent 'no value' with a sentinel object that implements <=> rather than nil.
  4. Wrap items in a Struct carrying priority plus payload so nil payloads become legal values inside the wrapper.

Example fix

// before
queue << config[:retry_after]   # nil when key missing -> ArgumentError

// after
queue << config.fetch(:retry_after, DEFAULT_RETRY_AFTER)
Defensive patterns

Strategy: validation

Validate before calling

queue << item unless item.nil?

Type guard

def enqueueable?(item)
  !item.nil? && item.respond_to?(:<=>)
end

Try / catch

begin
  queue << item
rescue ArgumentError => e
  raise unless e.message == 'cannot enqueue nil'
  logger.warn('skipped nil task')
end

Prevention

When it happens

Trigger: `queue.push(nil)`, `queue << nil`, or `queue.enq(nil)`; enqueueing `hash[key]` for a missing key; building the queue from a list containing nils (`from_list([1, nil, 2])` pushes each item, including the nil).

Common situations: Nulls from databases, config, or JSON parsed into scheduling queues; optional fields that end up nil; forgetting #compact on input arrays; using nil as a 'lowest priority' marker.

Related errors


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