Fix type-mixed rows_added_slice breaking refresh log ingestion

What does this MR do and why?

Since September 2023, no authorized_projects_refresh log line with rows_added_count > 0 has been indexed in Elasticsearch on GitLab.com. Kibana shows zero such documents over any time range, while documents with rows_deleted_count > 0 index normally (1,200+ in the last month). Meanwhile the Prometheus counter gitlab_authorized_projects_safety_net_refresh_rows_total{direction="added"}, incremented from the same value, shows added rows do occur (for example a ~557k-row burst on GitLab.com on 2026-08-25).

The cause is Users::RefreshAuthorizedProjectsService#log_refresh_details, which logs rows_added_slice as add.first(5).map(&:values). The add array holds hashes of {user_id:, project_id:, access_level:}, all integers. Commit ca040214 ("Write project_authorizations.is_unique on create") added ProjectAuthorizations::Changes#insert_all_in_batches, which mutates those same hash objects in place, setting attrs[:is_unique] = true, before calling insert_all. Logging happens after apply!, so every logged row is actually [user_id, project_id, access_level, true] - integers mixed with a boolean.

Elasticsearch flattens the nested arrays into one field, maps its type from the first (integer) value, and then throws a mapper parsing exception on the boolean, rejecting the whole document. Empty slices (no rows added) have no boolean and index fine, which is why only add-row documents are missing, and why the field doesn't even exist in the Kibana data view.

The fix logs the three integer attributes by name, row.values_at(:user_id, :project_id, :access_level), so the array stays homogeneous regardless of what ProjectAuthorizations::Changes adds to the hashes later. This follows GitLab's logging guideline that list elements in a log field must be the same type. The existing spec expectation is updated from [[user_id, project_id, access_level, true]] to [[user_id, project_id, access_level]].

How to set up and validate locally

  • Run bundle exec rspec spec/services/users/refresh_authorized_projects_service_spec.rb
  • Optionally, in a rails console, refresh a user with a missing authorization and confirm the logged rows_added_slice contains only integers.

Merge request reports

Loading
Loading