{"record":{"id":"c74b12479d5999cd","repo":"ruby-concurrency/concurrent-ruby","slug":"class-option-is-ignored-when-calling-on-context-c","errorCode":null,"errorMessage":":class option is ignored when calling on context class, use Actor.spawn instead","messagePattern":":class option is ignored when calling on context class, use Actor\\.spawn instead","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby-edge/concurrent/actor/context.rb","lineNumber":135,"sourceCode":"      def self.spawn(name_or_opts, *args, &block)\n        Actor.spawn to_spawn_options(name_or_opts, *args), &block\n      end\n\n      # behaves as {Concurrent::Actor.spawn!} but :class is auto-inserted based on receiver so it can be omitted.\n      def self.spawn!(name_or_opts, *args, &block)\n        Actor.spawn! to_spawn_options(name_or_opts, *args), &block\n      end\n\n      private\n\n      def initialize_core(core)\n        @core = Type! core, Core\n      end\n\n      def self.to_spawn_options(name_or_opts, *args)\n        if name_or_opts.is_a? ::Hash\n          if name_or_opts.key?(:class) && name_or_opts[:class] != self\n            raise ArgumentError,\n                  ':class option is ignored when calling on context class, use Actor.spawn instead'\n          end\n          name_or_opts.merge class: self\n        else\n          { class: self, name: name_or_opts, args: args }\n        end\n      end\n\n      # to avoid confusion with Kernel.spawn\n      undef_method :spawn\n    end\n\n    # Basic Context of an Actor. It supports only linking and it simply terminates on error.\n    # Uses {Behaviour.basic_behaviour_definition}:\n    #\n    # @abstract implement {AbstractContext#on_message}\n    class Context < AbstractContext\n      def behaviour_definition","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby-edge/concurrent/actor/context.rb#L117-L153","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Drop the `:class` key when spawning on the context class itself: `MyContext.spawn(name: 'worker')`.","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.","Sanitize the options hash before calling: `opts = opts.dup; opts.delete(:class)`.","Keep `class: MyContext` if you must preserve the key — a value matching the receiver is accepted."],"exampleFix":"// before\nactor = MyContext.spawn(class: OtherContext, name: 'worker')\n\n// after\nactor = Concurrent::Actor.spawn(class: OtherContext, name: 'worker')\n// or, when spawning MyContext itself:\nactor = MyContext.spawn(name: 'worker')","handlingStrategy":"validation","validationCode":"def spawn_context(klass, opts)\n  if opts.is_a?(Hash) && opts.key?(:class) && opts[:class] != klass\n    raise ArgumentError, \"#{klass} cannot spawn with class: #{opts[:class]}; use Concurrent::Actor.spawn\"\n  end\n  klass.spawn(opts)\nend","typeGuard":null,"tryCatchPattern":"begin\n  MyContext.spawn(opts)\nrescue ArgumentError => e\n  raise unless e.message.include?(':class option is ignored')\n  Concurrent::Actor.spawn(opts) # opts keeps its :class\nend","preventionTips":["Build spawn options without a :class key when spawning via a Context subclass.","Reserve the :class option for Concurrent::Actor.spawn / spawn!.","Route all spawns through one helper that enforces the option policy."],"tags":["concurrent-ruby","concurrent-ruby-edge","actor","spawn","argumenterror","options"],"backgroundTag":"conflicting-option-values","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}