{"record":{"id":"7a56ef728ec3733f","repo":"ruby-concurrency/concurrent-ruby","slug":"no-member-member-in-struct-7a56ef","errorCode":null,"errorMessage":"no member '#{member}' in struct","messagePattern":"no member '#(.+?)' in struct","errorType":"exception","errorClass":"NameError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb","lineNumber":69,"sourceCode":"      # @!visibility private\n      def ns_to_h\n        length.times.reduce({}){|memo, i| memo[self.class::MEMBERS[i]] = @values[i]; memo}\n      end\n\n      # @!macro struct_get\n      #\n      # @!visibility private\n      def ns_get(member)\n        if member.is_a? Integer\n          if member >= @values.length\n            raise IndexError.new(\"offset #{member} too large for struct(size:#{@values.length})\")\n          end\n          @values[member]\n        else\n          send(member)\n        end\n      rescue NoMethodError\n        raise NameError.new(\"no member '#{member}' in struct\")\n      end\n\n      # @!macro struct_equality\n      #\n      # @!visibility private\n      def ns_equality(other)\n        self.class == other.class && self.values == other.values\n      end\n\n      # @!macro struct_each\n      #\n      # @!visibility private\n      def ns_each\n        values.each{|value| yield value }\n      end\n\n      # @!macro struct_each_pair\n      #","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb#L51-L87","documentation":"When a non-Integer member is read, ns_get dispatches to the reader method via send(member); an undefined member raises NoMethodError, rescued and re-raised as NameError(\"no member 'x' in struct\"). This matches core Struct semantics: only members declared at definition can be read, and there is no dynamic field support.","triggerScenarios":"s[:typo] or s.typo where the member was never declared or was renamed; symbol-vs-string key drift when forwarding params; de-serializing JSON into a struct assuming extra keys are readable.","commonSituations":"Renaming a member in the definition but not at read sites; schema drift between producer and consumer of the struct; using symbol literals copied from a different struct.","solutions":["Check membership before dynamic reads: s.class.members.include?(key.to_sym)","Use to_h when you need Hash-like tolerant access (to_h returns only declared members)","Keep member lists in one constant shared between the definition and dynamic accessors"],"exampleFix":"# before\nCfg = Concurrent::ImmutableStruct.new(:host, :port)\nc = Cfg.new('localhost', 8080)\nv = c[:prot] # NameError\n\n# after\nkey = :port if Cfg.members.include?(:port)\nv = key && c[key]","handlingStrategy":"type-guard","validationCode":"key = key.to_sym if key.is_a?(String)\nstruct[key] if struct.class.members.include?(key)","typeGuard":"def known_member?(struct_class, key)\n  struct_class.members.include?(key.to_sym)\nend","tryCatchPattern":"begin\n  v = struct[key]\nrescue NameError => e\n  raise unless e.message.include?('no member')\n  v = struct.to_h[key.to_sym] # nil for extras; schema drift surfaced\nend","preventionTips":["Whitelist external keys against Klass.members before reads","Rename members with a deprecation alias period instead of a hard cut","Prefer to_h when bridging structs to string-keyed payloads"],"tags":["ruby","struct","abstract-struct","name-error","unknown-member"],"backgroundTag":"unknown-struct-member","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}