ruby-concurrency/concurrent-ruby · error · ArgumentError

:class option is ignored when calling on context class, use

Error message

:class option is ignored when calling on context class, use Actor.spawn instead

What it means

In the Edge Actor framework, every Concurrent::Actor::Context subclass gets a class-level `spawn` that always instantiates that same class: `to_spawn_options` merges `class: self` into the options. If the first argument is a Hash containing a `:class` key whose value differs from the context class you called `spawn` on, the library raises ArgumentError rather than silently ignoring your option. Passing `class: MyContext` (the same class) or omitting `:class` is fine. To spawn a different class, call Concurrent::Actor.spawn / spawn! directly with the `:class` option.

Source

Thrown at lib/concurrent-ruby-edge/concurrent/actor/context.rb:135

      def self.spawn(name_or_opts, *args, &block)
        Actor.spawn to_spawn_options(name_or_opts, *args), &block
      end

      # behaves as {Concurrent::Actor.spawn!} but :class is auto-inserted based on receiver so it can be omitted.
      def self.spawn!(name_or_opts, *args, &block)
        Actor.spawn! to_spawn_options(name_or_opts, *args), &block
      end

      private

      def initialize_core(core)
        @core = Type! core, Core
      end

      def self.to_spawn_options(name_or_opts, *args)
        if name_or_opts.is_a? ::Hash
          if name_or_opts.key?(:class) && name_or_opts[:class] != self
            raise ArgumentError,
                  ':class option is ignored when calling on context class, use Actor.spawn instead'
          end
          name_or_opts.merge class: self
        else
          { class: self, name: name_or_opts, args: args }
        end
      end

      # to avoid confusion with Kernel.spawn
      undef_method :spawn
    end

    # Basic Context of an Actor. It supports only linking and it simply terminates on error.
    # Uses {Behaviour.basic_behaviour_definition}:
    #
    # @abstract implement {AbstractContext#on_message}
    class Context < AbstractContext
      def behaviour_definition

View on GitHub (pinned to 0b88d5ff75)

Solutions

  1. Drop the `:class` key when spawning on the context class itself: `MyContext.spawn(name: 'worker')`.
  2. If a different actor class is intended, call `Concurrent::Actor.spawn(class: OtherContext, name: 'worker')` (options-hash form) instead of spawning via the context class.
  3. Sanitize the options hash before calling: `opts = opts.dup; opts.delete(:class)`.
  4. Keep `class: MyContext` if you must preserve the key — a value matching the receiver is accepted.

Example fix

// before
actor = MyContext.spawn(class: OtherContext, name: 'worker')

// after
actor = Concurrent::Actor.spawn(class: OtherContext, name: 'worker')
// or, when spawning MyContext itself:
actor = MyContext.spawn(name: 'worker')
Defensive patterns

Strategy: validation

Validate before calling

def spawn_context(klass, opts)
  if opts.is_a?(Hash) && opts.key?(:class) && opts[:class] != klass
    raise ArgumentError, "#{klass} cannot spawn with class: #{opts[:class]}; use Concurrent::Actor.spawn"
  end
  klass.spawn(opts)
end

Try / catch

begin
  MyContext.spawn(opts)
rescue ArgumentError => e
  raise unless e.message.include?(':class option is ignored')
  Concurrent::Actor.spawn(opts) # opts keeps its :class
end

Prevention

When it happens

Trigger: Calling `MyContext.spawn(class: OtherContext, name: 'x')` — hash-form first argument with a `:class` key not equal to `MyContext`. Also `MyContext.spawn({class: OtherContext, args: [1]})`. NOT triggered by `MyContext.spawn('name')` (string form builds `{class: self, name: ...}`) or by `MyContext.spawn(class: MyContext, ...)` (equal class is allowed).

Common situations: Copy-pasting a generic `Actor.spawn(class: ..., name: ...)` call onto a Context subclass; a shared spawn helper that builds one options hash for both entry points; refactors where the receiver class changed but the stale `:class` option stayed in the hash.

Related errors


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