{"record":{"id":"19cf90a200844b20","repo":"ruby-concurrency/concurrent-ruby","slug":"struct-size-differs","errorCode":null,"errorMessage":"struct size differs","messagePattern":"struct size differs","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb","lineNumber":146,"sourceCode":"\n      # @!visibility private\n      def pr_underscore(clazz)\n        word = clazz.to_s.dup # dup string to workaround JRuby 9.2.0.0 bug https://github.com/jruby/jruby/issues/5229\n        word.gsub!(/::/, '/')\n        word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\\1_\\2')\n        word.gsub!(/([a-z\\d])([A-Z])/,'\\1_\\2')\n        word.tr!(\"-\", \"_\")\n        word.downcase!\n        word\n      end\n\n      # @!visibility private\n      def self.define_struct_class(parent, base, name, members, &block)\n        clazz = Class.new(base || Object) do\n          include parent\n          self.const_set(:MEMBERS, members.collect{|member| member.to_s.to_sym}.freeze)\n          def ns_initialize(*values)\n            raise ArgumentError.new('struct size differs') if values.length > length\n            @values = values.fill(nil, values.length..length-1)\n          end\n        end\n        unless name.nil?\n          begin\n            parent.send :remove_const, name if parent.const_defined?(name, false)\n            parent.const_set(name, clazz)\n            clazz\n          rescue NameError\n            raise NameError.new(\"identifier #{name} needs to be constant\")\n          end\n        end\n        members.each_with_index do |member, index|\n          clazz.send :remove_method, member if clazz.instance_methods(false).include? member\n          clazz.send(:define_method, member) do\n            @values[index]\n          end\n        end","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb#L128-L164","documentation":"The generated struct class's ns_initialize accepts at most as many positional values as there are members; a longer argument list raises ArgumentError('struct size differs'). Fewer values are padded with nil, so only the upper bound is enforced. This is the concurrent structs' equivalent of core Struct's arity check.","triggerScenarios":"Point.new(1, 2, 3) for Point defined with 2 members; K.new(*arr) where arr outgrew the member list after a data change; passing a defaulted splat whose length varies per caller.","commonSituations":"A struct definition is trimmed (member removed) while some constructors still pass the old arity; splatting external data (CSV rows, JSON arrays) without length validation; merging two structs' constructors during a refactor.","solutions":["Validate before splatting: raise ArgumentError, \"expected <= #{K.members.size} values\" if arr.length > K.members.size","If truncation is acceptable by design, slice explicitly: K.new(*arr.first(K.members.size))","After changing a member list, update every construction site of that struct class"],"exampleFix":"# before\nPoint = Concurrent::MutableStruct.new(:x, :y)\npt = Point.new(*csv_row) # raises when csv_row has 3+ columns\n\n# after\nraise ArgumentError, 'row too long' if csv_row.length > Point.members.size\npt = Point.new(*csv_row.first(Point.members.size))","handlingStrategy":"validation","validationCode":"max = Klass.members.size\nraise ArgumentError, \"#{values.length} values for #{max} members\" if values.length > max\nKlass.new(*values)","typeGuard":null,"tryCatchPattern":"begin\n  Klass.new(*values)\nrescue ArgumentError => e\n  raise unless e.message == 'struct size differs'\n  Klass.new(*values.first(Klass.members.size)) # explicit truncation policy\nend","preventionTips":["Validate splat length against members.size before constructing","Update all construction sites when editing a member list","Add an arity spec for each generated struct class"],"tags":["ruby","struct","abstract-struct","argument-error","arity-mismatch"],"backgroundTag":"argument-count-mismatch","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}