GraphQL API returns 500 error when querying pipelines with scope: TAGS or BRANCHES

Summary

GraphQL API returns 500 error when querying pipelines with scope: TAGS (or BRANCHES) parameter.

Steps to reproduce

  1. Access the GitLab GraphQL API (e.g. via https://gitlab.com/-/graphql-explorer)
  2. Execute the following GraphQL query:
{
 group(fullPath: "gitlab-com/support") {
   id
   projects(includeSubgroups: true, first: 10, after: "") {
     nodes {
       id
       tagPipelines: pipelines(first: 1, scope: TAGS) {
         nodes {
           id
         }
       }
     }
   }
 }
}
  1. Observe the 500 error response

Example Project

The issue occurs in the gitlab-com/support group.

What is the current bug behavior?

The API returns a 500 Internal Server Error with the following error message in logs:

The order on the scope does not support keyset pagination. You might need to define a custom Order object.

The error is caused by Gitlab::Pagination::Keyset::UnsupportedScopeOrder exception as shown in the logs.

What is the expected correct behavior?

The API should successfully return pipeline data when filtering by scope: TAGS. This worked until recently as indicated by the customer reporting this as a regression.

Relevant logs and/or screenshots

Error Response
{
  "errors": [
    {
      "name": "ServerError",
      "response": {},
      "statusCode": 500,
      "result": {
        "errors": [
          {
            "message": "Internal server error"
          }
        ]
      },
      "message": "Response not successful: Received status code 500",
      "stack": "ServerError: Response not successful: Received status code 500\n    at r (https://gitlab.com/assets/webpack/main.5a1fb859.chunk.js:69:129125)\n    at https://gitlab.com/assets/webpack/main.5a1fb859.chunk.js:63:89413"
    }
  ]
}
Application Logs
    "json.exception.message.keyword": [
      "The order on the scope does not support keyset pagination. You might need to define a custom Order object.\n\nSee https://docs.gitlab.com/ee/development/database/keyset_pagination.html#complex-order-configuration\n\nOr the Gitlab::Pagination::Keyset::Order class for examples\n"

Full stack trace shows the error originates in the keyset pagination implementation for GraphQL queries.

Output of checks

This bug happens on GitLab.com

Results of GitLab environment info

Expand for output related to GitLab environment info

(For installations with omnibus-gitlab package run and paste the output of: \`sudo gitlab-rake gitlab:env:info\`) (For installations from source run and paste the output of: \`sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production\`)

Results of GitLab application Check

Expand for output related to the GitLab application check

(For installations with omnibus-gitlab package run and paste the output of: \`sudo gitlab-rake gitlab:check SANITIZE=true\`) (For installations from source run and paste the output of: \`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true\`) (we will only investigate if the tests are passing)

Possible fixes

Note: I used AI to help me analyze the code base and development documentation to provide possible fixes for this issue.

After analyzing the keyset pagination implementation in lib/gitlab/graphql/pagination/keyset/connection.rb and the keyset pagination documentation, there are two likely causes:

  1. The TAGS scope is using a complex ORDER BY clause that the SimpleOrderBuilder cannot automatically handle
  2. The ordering might not include a stable tie-breaker (like id) to ensure distinct values

Based on the documentation, here are the recommended fixes:

  1. Define a custom Order object for the TAGS scope in the Pipeline model similar to the documented examples:
order = Gitlab::Pagination::Keyset::Order.build([
  Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
    attribute_name: 'primary_sorting_column',
    order_expression: Pipeline.arel_table[:your_column].desc,
    nullable: :not_nullable  # adjust based on column nullability
  ),
  Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
    attribute_name: 'id',
    order_expression: Pipeline.arel_table[:id].desc,
    nullable: :not_nullable
  )
])
  1. If the TAGS scope uses function-based ordering, ensure the expression is added to projections:
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
  attribute_name: 'ordering_expression',
  order_expression: your_expression,
  add_to_projections: true,
  nullable: :not_nullable
)
  1. For complex queries with OR conditions, consider using the UNION optimization by passing:
keyset_order_options: { use_union_optimization: true }

Relevant code paths:

  • lib/gitlab/graphql/pagination/keyset/connection.rb
  • Pipeline model's TAGS scope definition
  • Consider adding a supported keyset ordering configuration to the Pipeline model:
def self.supported_keyset_orderings
  { your_column: [:asc, :desc] }
end

Relevant code paths:

  • lib/gitlab/graphql/pagination/keyset/connection.rb
  • Pipeline resolver implementation for TAGS scope
Edited by Christopher Mutua