ruby-concurrency/concurrent-ruby · error · ArgumentError

wrong number of arguments (0 for 1+)

Error message

wrong number of arguments (0 for 1+)

What it means

Concurrent::ImmutableStruct.new is the class-factory call (like Ruby's Struct.new): it defines a new immutable struct class from a list of member names. Passing zero arguments raises ArgumentError 'wrong number of arguments (0 for 1+)' because a struct with no members cannot be defined.

Source

Thrown at lib/concurrent-ruby/concurrent/immutable_struct.rb:85

    # @!macro struct_select
    def select(&block)
      return enum_for(:select) unless block_given?
      ns_select(&block)
    end

    private

    # @!visibility private
    def initialize_copy(original)
      super(original)
      ns_initialize_copy
    end

    # @!macro struct_new
    def self.new(*args, &block)
      clazz_name = nil
      if args.length == 0
        raise ArgumentError.new('wrong number of arguments (0 for 1+)')
      elsif args.length > 0 && args.first.is_a?(String)
        clazz_name = args.shift
      end
      FACTORY.define_struct(clazz_name, args, &block)
    end

    FACTORY = Class.new(Synchronization::LockableObject) do
      def define_struct(name, members, &block)
        synchronize do
          Synchronization::AbstractStruct.define_struct_class(ImmutableStruct, Synchronization::Object, name, members, &block)
        end
      end
    end.new
    private_constant :FACTORY
  end
end

View on GitHub (pinned to 0b88d5ff75)

Solutions

  1. Ensure at least one member symbol/string is passed: Concurrent::ImmutableStruct.new(:a, :b)
  2. When members come from a dynamic list, guard it first: raise a clear error (or skip creation) if the list is empty
  3. Double-check splats: log fields.inspect before the call when the list is computed

Example fix

# before
fields = query_columns(table) # => []
Klass = Concurrent::ImmutableStruct.new(*fields)

# after
fields = query_columns(table)
raise ArgumentError, "#{table} has no columns; cannot build struct" if fields.empty?
Klass = Concurrent::ImmutableStruct.new(*fields)
Defensive patterns

Strategy: validation

Validate before calling

raise ArgumentError, 'at least one struct member required' if members.empty?
Klass = Concurrent::ImmutableStruct.new(*members)

Type guard

->(list) { list.is_a?(Array) && list.all? { |m| m.is_a?(Symbol) || m.is_a?(String) } && !list.empty? }

Try / catch

begin
  Concurrent::ImmutableStruct.new(*members)
rescue ArgumentError => e
  raise SchemaError, "cannot define struct: #{e.message}"
end

Prevention

When it happens

Trigger: Concurrent::ImmutableStruct.new with nothing after it; Concurrent::ImmutableStruct.new(*fields) where fields is an empty array (dynamic schemas, DB-driven columns); splatting a list that came back empty from an API or query result.

Common situations: Generating struct classes from data schemas (CSV headers, DB columns, JSON keys) where the source can legitimately be empty; refactoring member lists into constants and losing the contents; confusion between the factory call and instantiating the produced class.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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