{"record":{"id":"e504bf709cb6f7f9","repo":"gitlabhq/gitlabhq","slug":"invalid-relation-entry-inspect","errorCode":null,"errorMessage":"Invalid relation: #{entry.inspect}","messagePattern":"Invalid relation: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"app/models/ci/preloaders/commit_status_preloader.rb","lineNumber":41,"sourceCode":"      def objects(klass)\n        @statuses.select { |job| job.is_a?(klass) }\n      end\n\n      def associations(klass, relations)\n        klass_reflections = klass.reflections.keys.map(&:to_sym).to_set\n\n        result = []\n        relations.each do |entry|\n          if entry.respond_to?(:to_sym)\n            result << entry.to_sym if klass_reflections.include?(entry.to_sym)\n          elsif entry.is_a?(Hash)\n            entry = entry.select do |key, _value|\n              klass_reflections.include?(key.to_sym)\n            end\n\n            result << entry if entry.present?\n          else\n            raise ArgumentError, \"Invalid relation: #{entry.inspect}\"\n          end\n        end\n\n        result\n      end\n    end\n  end\nend\n","sourceCodeStart":23,"sourceCodeEnd":50,"githubUrl":"https://github.com/gitlabhq/gitlabhq/blob/55ee20384a1f55cb0e362dee1d07149613b1b9bf/app/models/ci/preloaders/commit_status_preloader.rb#L23-L50","documentation":"Ci::Preloaders::CommitStatusPreloader's relation filter raises ArgumentError, \"Invalid relation: #{entry.inspect}\" when an element of the relations argument is neither an object responding to to_sym (Symbol/String) nor a Hash. Each entry must resolve to a reflection name on the klass (commit statuses) or a Hash whose keys are reflection names; anything else — Integer, Array, nil — is rejected as invalid.","triggerScenarios":"Calling the preloader with nested arrays like [:stage, [:tags]] where the inner array element is itself an Array; passing nil inside the list (e.g. from params[relation]&.to_a); passing an AR object or integer id instead of a relation name.","commonSituations":"Building preload lists dynamically from user-supplied `includes` parameters; merging hardcoded and computed relation lists where one side yields arrays or nils; refactoring symbol lists into nested structures.","solutions":["Pass a flat array of Symbols/Strings and/or Hashes only, e.g. [:project, :runner, { tags: :pipeline }]","Flatten and compact the list before calling: relations.flatten.compact","Filter names against the model's reflections before invoking if the list is user-derived"],"exampleFix":"# before\nrelations = [:project, [:runner, nil]] # inner Array + nil entries -> raises\nCommitStatusPreloader.new(statuses).preload(relation_names: relations)\n\n# after\nrelations = [:project, :runner, { tags: {} }].flatten.compact\nCommitStatusPreloader.new(statuses).preload(relation_names: relations)","handlingStrategy":"type-guard","validationCode":"relations = relations.flatten.compact\nraise ArgumentError, relations.inspect unless relations.all? { |r| r.respond_to?(:to_sym) || r.is_a?(Hash) }\n# names must also exist as reflections on the preloaded klass\nvalid = Ci::Build.reflect_on_all_associations.map { |_, rel| rel.name.to_s }\nrelations.select! { |r| valid.include?(r.to_s) } unless relations.all?(Hash)","typeGuard":"def valid_preload_entries?(entries)\n  entries.flatten.compact.all? { |e| e.respond_to?(:to_sym) || e.is_a?(Hash) }\nend","tryCatchPattern":"begin\n  Ci::Preloaders::CommitStatusPreloader.new(statuses).preload(relation_names: relations)\nrescue ArgumentError => e\n  raise unless e.message.start_with?('Invalid relation:')\n  # log the inspected entry and fall back to a hardcoded safe relation list\nend","preventionTips":["Keep preload relation lists as flat symbol/hash literals, not dynamically nested arrays","Never feed user-supplied includes parameters straight into preloaders","Compact and flatten merged relation lists before use"],"tags":["gitlab","ci","preloader","activerecord","argument-validation"],"backgroundTag":"invalid-preload-argument","analyzedSha":"55ee20384a1f55cb0e362dee1d07149613b1b9bf","analyzedAt":"2026-08-21T14:22:27.782Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}