ruby-concurrency/concurrent-ruby · error · ArgumentError

unrecognized error mode

Error message

unrecognized error mode

What it means

Concurrent::Agent accepts an :error_mode option choosing failure behavior - :continue (keep processing subsequent actions after an error) or :fail (halt pending actions until restart) - validated against the frozen ERROR_MODES whitelist. Any other value raises ArgumentError at construction time.

Source

Thrown at lib/concurrent-ruby/concurrent/agent.rb:495

      # @param [Array<Concurrent::Agent>] agents the Agents on which to wait
      # @return [Boolean] true if all actions complete before timeout
      #
      # @raise [Concurrent::TimeoutError] when timeout is reached
      # @!macro agent_await_warning
      def await_for!(timeout, *agents)
        raise Concurrent::TimeoutError unless await_for(timeout, *agents)
        true
      end
    end

    private

    def ns_initialize(initial, opts)
      @error_mode    = opts[:error_mode]
      @error_handler = opts[:error_handler]

      if @error_mode && !ERROR_MODES.include?(@error_mode)
        raise ArgumentError.new('unrecognized error mode')
      elsif @error_mode.nil?
        @error_mode = @error_handler ? :continue : :fail
      end

      @error_handler ||= DEFAULT_ERROR_HANDLER
      @validator     = opts.fetch(:validator, DEFAULT_VALIDATOR)
      @current       = Concurrent::AtomicReference.new(initial)
      @error         = Concurrent::AtomicReference.new(nil)
      @caller        = Concurrent::ThreadLocalVar.new(nil)
      @queue         = []

      self.observers = Collection::CopyOnNotifyObserverSet.new
    end

    def enqueue_action_job(action, args, executor)
      raise ArgumentError.new('no action given') unless action
      job = Job.new(action, args, executor, @caller.value || Thread.current.object_id)
      synchronize { ns_enqueue_job(job) }

View on GitHub (pinned to 0b88d5ff75)

Solutions

  1. Use one of the two supported symbols: :continue or :fail.
  2. Validate and default at the edge: raise on unknown config values at load time, symbolize strings with .to_sym once.
  3. If you need default behavior, omit :error_mode entirely - it defaults to :continue when an :error_handler is given, else :fail.

Example fix

# before
agent = Concurrent::Agent.new(0, error_mode: :fail_fast)

# after
agent = Concurrent::Agent.new(0, error_mode: :fail)
Defensive patterns

Strategy: type-guard

Type guard

ERROR_MODES = %i[continue fail].freeze

def valid_error_mode?(mode)
  ERROR_MODES.include?(mode)
end

mode = opts.fetch(:error_mode, :fail)
raise ArgumentError, "error_mode must be one of #{ERROR_MODES}" unless valid_error_mode?(mode)
agent = Concurrent::Agent.new(initial, error_mode: mode)

Try / catch

begin
  agent = Concurrent::Agent.new(initial, **opts)
rescue ArgumentError => e
  raise ConfigError, "bad agent options: #{e.message}"
end

Prevention

When it happens

Trigger: Concurrent::Agent.new(0, error_mode: :fail_fast), :continue_on_error, :raise, :ignore, or the string 'continue' (strings do not match the symbol whitelist).

Common situations: Guessing Clojure-flavored or custom names for the mode; reading the mode from config/ENV without symbolizing or validating; copying agent setup between projects or versions where expected option names differ.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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