gitlabhq/gitlabhq · error · DeploymentsFinder::InefficientQueryError

`updated_at` filter requires `updated_at` sort

Error message

`updated_at` filter requires `updated_at` sort

What it means

DeploymentsFinder#validate! raises InefficientQueryError when the updated_at filter is present but the sort is not order_by=updated_at. The filter only stays efficient when results are scanned in updated_at order via its supporting index, so GitLab requires sort and filter to match and returns HTTP 400 otherwise.

Source

Thrown at app/finders/deployments_finder.rb:61

  def execute
    items = init_collection
    items = by_updated_at(items)
    items = by_finished_at(items)
    items = by_environment(items)
    items = by_status(items)
    items = preload_associations(items)
    sort(items)
  end

  private

  def validate!
    if filter_by_updated_at? && filter_by_finished_at?
      raise InefficientQueryError, 'Both `updated_at` filter and `finished_at` filter can not be specified'
    end

    if filter_by_updated_at? && !order_by_updated_at?
      raise InefficientQueryError, '`updated_at` filter requires `updated_at` sort'
    end

    if filter_by_finished_at? && !order_by_finished_at?
      raise InefficientQueryError, '`finished_at` filter requires `finished_at` sort.'
    end

    if order_by_finished_at? && !(filter_by_finished_at? || filter_by_finished_statuses?)
      raise InefficientQueryError,
        '`finished_at` sort requires `finished_at` filter or a filter with at least one of the finished statuses.'
    end

    if filter_by_finished_at? && !filter_by_successful_deployment?
      raise InefficientQueryError, '`finished_at` filter must be combined with `success` status filter.'
    end

    if filter_by_environment_name? && !params[:project].present?
      raise InefficientQueryError, '`environment` name filter must be combined with `project` scope.'
    end

View on GitHub (pinned to 55ee20384a)

Solutions

  1. Add order_by=updated_at (with sort=asc or sort=desc) whenever you send updated_after/updated_before.
  2. If you must keep a different sort, drop the updated_at filter entirely.
  3. Use the updated_at ordering together with keyset pagination for large result sets.

Example fix

# before
GET /api/v4/projects/42/deployments?updated_after=2026-01-01T00:00:00Z
# => 400 `updated_at` filter requires `updated_at` sort

# after
GET /api/v4/projects/42/deployments?updated_after=2026-01-01T00:00:00Z&order_by=updated_at&sort=desc
Defensive patterns

Strategy: validation

Validate before calling

if params[:updated_after] || params[:updated_before]
  params[:order_by] ||= 'updated_at'
  raise ArgumentError, 'updated_at filter needs order_by=updated_at' unless params[:order_by] == 'updated_at'
end

Prevention

When it happens

Trigger: GET /api/v4/projects/:id/deployments?updated_after=... sent without order_by, or with order_by=id / order_by=finished_at; SDK defaults that force order_by=id; pagination params copied from another endpoint.

Common situations: Clients adding time filters to an existing sorted listing; GraphQL/Automation templates that preset a default sort; keyset pagination code that sets its own order_by.

Related errors


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