ruby-concurrency/concurrent-ruby · error · ArgumentError

cannot enqueue nil

Error message

cannot enqueue nil

What it means

This is the pure-Ruby heap engine used by Concurrent::PriorityQueue on non-JRuby platforms. As with the Java variant, nil is the queue's 'empty' sentinel (pop returns nil when the heap is exhausted), so push rejects nil items with ArgumentError to keep a stored nil distinguishable from an empty queue.

Source

Thrown at lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb:79

        empty? ? nil : @queue[1]
      end

      # @!macro priority_queue_method_pop
      def pop
        return nil if empty?
        max = @queue[1]
        swap(1, @length)
        @length -= 1
        sink(1)
        @queue.pop
        max
      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?
        @length += 1
        @queue << item
        swim(@length)
        true
      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

      private

      # Exchange the values at the given indexes within the internal array.

View on GitHub (pinned to 0b88d5ff75)

Solutions

  1. Skip or filter nils before enqueueing: `items.compact.each { |i| queue << i }`.
  2. Substitute a real default via fetch for values destined for the queue.
  3. Use a null-object sentinel (with <=> defined) or a wrapper Struct when 'absent' must be queued.
  4. Remember items must be mutually comparable anyway — validate comparability along with non-nilness.

Example fix

// before
items.each { |i| queue << i }   # i is nil for missing entries -> ArgumentError

// after
items.compact.each { |i| queue << i }
Defensive patterns

Strategy: validation

Validate before calling

items.compact.each { |i| queue << i }

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 item')
end

Prevention

When it happens

Trigger: `queue.push(nil)`, `queue << nil`, `queue.enq(nil)`; `queue << record[:deadline]` where the field is absent; from_list over an array containing nils.

Common situations: Optional or missing values from config, APIs, or database rows flowing into a scheduling queue; nil used as a placeholder for 'not yet computed'; skipping #compact on bulk input.

Related errors


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