gitlabhq/gitlabhq · error · ArgumentError

pipeline not fully loaded

Error message

pipeline not fully loaded

What it means

Ci::Pipeline#age_in_minutes raises ArgumentError, 'pipeline not fully loaded' when the in-memory pipeline object lacks the created_at attribute (has_attribute?(:created_at) is false). This happens when the record was instantiated from a column projection that did not include created_at — the method cannot compute an age from a missing timestamp. Unpersisted records return 0 earlier, so only partially selected persisted rows reach the raise.

Source

Thrown at app/models/ci/pipeline.rb:1855

      self.builds.latest.build_matchers(project)
    end

    def cluster_agent_authorizations
      strong_memoize(:cluster_agent_authorizations) do
        ::Clusters::Agents::Authorizations::CiAccess::Finder.new(project).execute
      end
    end

    def has_test_reports?
      strong_memoize(:has_test_reports) do
        latest_report_builds_in_self_and_project_descendants(::Ci::JobArtifact.of_report_type(:test)).exists?
      end
    end

    def age_in_minutes
      return 0 unless persisted?

      raise ArgumentError, 'pipeline not fully loaded' unless has_attribute?(:created_at)

      return 0 unless created_at

      (Time.current - created_at).ceil / 60
    end

    def merge_request_diff
      return unless merge_request?

      merge_request.merge_request_diff_for(merge_request_diff_sha, order_by: :id_desc)
    end

    def auto_cancel_on_job_failure
      pipeline_metadata&.auto_cancel_on_job_failure || 'none'
    end

    def auto_cancel_on_new_commit
      pipeline_metadata&.auto_cancel_on_new_commit || 'conservative'

View on GitHub (pinned to 55ee20384a)

Solutions

  1. Include created_at in the query projection: .select(:id, :status, :created_at)
  2. Or reload the record before computing: pipeline.reload.age_in_minutes
  3. Return early in caller code when !pipeline.has_attribute?(:created_at) instead of relying on the raise

Example fix

# before
pipelines = project.ci_pipelines.select(:id, :status).limit(10)
pipelines.each { |p| puts p.age_in_minutes } # raises 'pipeline not fully loaded'

# after
pipelines = project.ci_pipelines.select(:id, :status, :created_at).limit(10)
pipelines.each { |p| puts p.age_in_minutes }
Defensive patterns

Strategy: type-guard

Validate before calling

# Ensure the instantiated row carries the column before computing age
pipeline.reload unless pipeline.has_attribute?(:created_at)
pipeline.age_in_minutes

Type guard

def pipeline_age_computable?(pipeline)
  pipeline.has_attribute?(:created_at)
end

Try / catch

begin
  age = pipeline.age_in_minutes
rescue ArgumentError => e
  raise unless e.message == 'pipeline not fully loaded'
  age = pipeline.reload.age_in_minutes
end

Prevention

When it happens

Trigger: Calling age_in_minutes on a pipeline from a scoped select, e.g. project.ci_pipelines.select(:id, :status).first.age_in_minutes; instantiating Ci::Pipeline.new(id: some_id) without created_at where persisted? checks pass via assigns (or from a pluck-built struct); loading through a custom from/subquery projection that omits created_at.

Common situations: Performance-tuned queries that select only id/status for large pipeline lists, then calling a convenience method that needs created_at; reporting code reusing minimal projections; specs building pipeline doubles with partial attributes.

Related errors


AI-assisted analysis of gitlabhq/gitlabhq@55ee20384a (2026-08-21). Data as JSON: /api/errors/8b8665f01c5e0a3f. Report an issue: GitHub.