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
- Ensure at least one member symbol/string is passed: Concurrent::ImmutableStruct.new(:a, :b)
- When members come from a dynamic list, guard it first: raise a clear error (or skip creation) if the list is empty
- 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
- Validate dynamic schema lists (columns, keys) at the data boundary before generating classes
- Cache generated struct classes keyed by the member list to avoid repeated metaprogramming
- Fail with a domain-specific error that names the empty source (table, feed) instead of the raw ArgumentError
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
- wrong number of arguments (0 for 1+)
- no member '#{member}' in struct
- `min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}
- `min_threads` cannot be more than `max_threads`
- no block given
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/19f621f466efd358.
Report an issue: GitHub.