User state transition to non-active can produce a 500 error due to projects_star_count_positive constraint
Summary
A check constraint (projects_star_count_positive) was added to ensure a project's star_count is non-negative. However, when a user is transitioned away from an active state, it is possible to decrement the count to below 0 resulting in a 500 error.
Customer experienced this on emergency ticket: Zendesk ticket (internal)
Related:
- Project can have a negative STAR count resultin... (#394810 - closed)
- Add check constraint to ensure star_count is no... (!142527 - merged)
- Do not count stars of blocked users (!100023 - merged)
Steps to reproduce
Unclear at this time how a project got into this state for the customer. However, it presented itself because the user's didn't have the necessary group's in their SAML response that aligned with their required_groups. This resulted in the user being system blocked, decrementing star_count below zero and surfacing a 500 to the user.
What is the current bug behavior?
A 500 error occurs.
What is the expected correct behavior?
Logic to prevent negative star_count on user state transition is added. This would then allow surfacing an appropriate message depending on the situation.
Relevant logs and/or screenshots
Click to expand
{
"method": "POST",
"path": "/users/auth/saml/callback",
"format": "html",
"controller": "OmniauthCallbacksController",
"action": "saml",
"status": 500,
"time": "2024-09-11T20:29:49.864Z",
"params": [
{
"key": "SAMLResponse",
"value": "[FILTERED]"
},
{
"key": "RelayState",
"value": ""
}
],
"correlation_id": "01J7HCEB4XYY225PMRSTYRSQ9Y",
"meta.caller_id": "OmniauthCallbacksController#saml",
"meta.remote_ip": "-",
"meta.feature_category": "system_access",
"meta.user": "-",
"meta.user_id": 21,
"meta.client_id": "user/21",
"remote_ip": "-",
"user_id": 21,
"username": "-",
"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
"queue_duration_s": 0.011695,
"request_urgency": "default",
"target_duration_s": 1,
"redis_calls": 12,
"redis_allowed_cross_slot_calls": 1,
"redis_duration_s": 0.004105,
"redis_read_bytes": 1339,
"redis_write_bytes": 2055,
"redis_db_load_balancing_calls": 2,
"redis_db_load_balancing_duration_s": 0.000343,
"redis_db_load_balancing_write_bytes": 106,
"redis_feature_flag_calls": 2,
"redis_feature_flag_duration_s": 0.000565,
"redis_feature_flag_read_bytes": 396,
"redis_feature_flag_write_bytes": 138,
"redis_queues_calls": 3,
"redis_queues_duration_s": 0.001049,
"redis_queues_read_bytes": 124,
"redis_queues_write_bytes": 966,
"redis_queues_metadata_calls": 2,
"redis_queues_metadata_duration_s": 0.001345,
"redis_queues_metadata_read_bytes": 4,
"redis_queues_metadata_write_bytes": 236,
"redis_sessions_calls": 3,
"redis_sessions_allowed_cross_slot_calls": 1,
"redis_sessions_duration_s": 0.000803,
"redis_sessions_read_bytes": 815,
"redis_sessions_write_bytes": 609,
"db_count": 18,
"db_write_count": 5,
"db_cached_count": 0,
"db_txn_count": 1,
"db_replica_txn_count": 0,
"db_primary_txn_count": 0,
"db_main_txn_count": 1,
"db_ci_txn_count": 0,
"db_main_replica_txn_count": 0,
"db_ci_replica_txn_count": 0,
"db_replica_count": 0,
"db_primary_count": 18,
"db_main_count": 18,
"db_ci_count": 0,
"db_main_replica_count": 0,
"db_ci_replica_count": 0,
"db_replica_cached_count": 0,
"db_primary_cached_count": 0,
"db_main_cached_count": 0,
"db_ci_cached_count": 0,
"db_main_replica_cached_count": 0,
"db_ci_replica_cached_count": 0,
"db_replica_wal_count": 0,
"db_primary_wal_count": 0,
"db_main_wal_count": 0,
"db_ci_wal_count": 0,
"db_main_replica_wal_count": 0,
"db_ci_replica_wal_count": 0,
"db_replica_wal_cached_count": 0,
"db_primary_wal_cached_count": 0,
"db_main_wal_cached_count": 0,
"db_ci_wal_cached_count": 0,
"db_main_replica_wal_cached_count": 0,
"db_ci_replica_wal_cached_count": 0,
"db_replica_txn_max_duration_s": 0.0,
"db_primary_txn_max_duration_s": 0.0,
"db_main_txn_max_duration_s": 0.035,
"db_ci_txn_max_duration_s": 0.0,
"db_main_replica_txn_max_duration_s": 0.0,
"db_ci_replica_txn_max_duration_s": 0.0,
"db_replica_txn_duration_s": 0.0,
"db_primary_txn_duration_s": 0.0,
"db_main_txn_duration_s": 0.035,
"db_ci_txn_duration_s": 0.0,
"db_main_replica_txn_duration_s": 0.0,
"db_ci_replica_txn_duration_s": 0.0,
"db_replica_duration_s": 0.0,
"db_primary_duration_s": 0.025,
"db_main_duration_s": 0.025,
"db_ci_duration_s": 0.0,
"db_main_replica_duration_s": 0.0,
"db_ci_replica_duration_s": 0.0,
"cpu_s": 0.225336,
"mem_objects": 117442,
"mem_bytes": 8482696,
"mem_mallocs": 48323,
"mem_total_bytes": 13180376,
"pid": 2365908,
"worker_id": "puma_0",
"rate_limiting_gates": [],
"exception.class": "ActiveRecord::StatementInvalid",
"exception.message": "PG::CheckViolation: ERROR: new row for relation \"projects\" violates check constraint \"projects_star_count_positive\"\nDETAIL: Failing row contains (10, dreamfyre, dreamfyre, You ..., 2022-07-09 00:01:57.23496, 2024-08-10 15:49:08.570311, 1, 15, 2024-08-10 15:49:08.570311, null, 0, f, null, null, -1, f, null, null, 0, t, f, null, f, null, null, null, t, null, t, 3600, f, f, t, f, 2024-08-13 22:20:20.18985, f, t, default, null, t, f, null, null, <p data-sourcepos=\"1:1-1:79\" dir=\"auto\">You can't quantify the s..., f, null, t, 1, t, 2162688, null, 2023-03-23 00:06:14.273062, null, 2, f, null, null, null, null, null, null, t, null, t, f, null, ivk/OIvl+rqyrnZwwG+X4jsitm+yY1HEhqruSwPAFdf/MdIxhIgLM9aXUHez, null, t, null, null, null, null, null, null, t, null, null, t, null, 24, f, 1).\n",
"exception.backtrace": [
"activerecord (7.0.8.4) lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `block (2 levels) in exec_no_cache'",
"activesupport (7.0.8.4) lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'",
"activesupport (7.0.8.4) lib/active_support/dependencies/interlock.rb:41:in `permit_concurrent_loads'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/postgresql_adapter.rb:767:in `block in exec_no_cache'",
"activesupport (7.0.8.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'",
"activesupport (7.0.8.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'",
"activesupport (7.0.8.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'",
"activesupport (7.0.8.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/abstract_adapter.rb:752:in `block in log'",
"activesupport (7.0.8.4) lib/active_support/notifications/instrumenter.rb:24:in `instrument'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/abstract_adapter.rb:743:in `log'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/postgresql_adapter.rb:766:in `exec_no_cache'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/postgresql_adapter.rb:745:in `execute_and_clear'",
"marginalia (1.11.1) lib/marginalia.rb:91:in `execute_and_clear_with_marginalia'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/postgresql/database_statements.rb:67:in `exec_delete'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/abstract/database_statements.rb:175:in `update'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/abstract/query_cache.rb:22:in `update'",
"lib/gitlab/database/load_balancing/connection_proxy.rb:127:in `public_send'",
"lib/gitlab/database/load_balancing/connection_proxy.rb:127:in `block in write_using_load_balancer'",
"lib/gitlab/database/load_balancing/load_balancer.rb:141:in `block in read_write'",
"lib/gitlab/database/load_balancing/load_balancer.rb:228:in `retry_with_backoff'",
"lib/gitlab/database/load_balancing/load_balancer.rb:130:in `read_write'",
"lib/gitlab/database/load_balancing/connection_proxy.rb:126:in `write_using_load_balancer'",
"lib/gitlab/database/load_balancing/connection_proxy.rb:61:in `block (2 levels) in <class:ConnectionProxy>'",
"activerecord (7.0.8.4) lib/active_record/relation.rb:485:in `update_all'",
"activerecord (7.0.8.4) lib/active_record/relation.rb:533:in `update_counters'",
"app/models/user.rb:583:in `block (3 levels) in <class:User>'",
"lib/gitlab/database/query_analyzers/prevent_cross_database_modification.rb:29:in `temporary_ignore_tables_in_transaction'",
"app/models/concerns/cross_database_ignored_tables.rb:8:in `temporary_ignore_cross_database_tables'",
"app/models/user.rb:580:in `block (2 levels) in <class:User>'",
"state_machines (0.5.0) lib/state_machines/eval_helpers.rb:79:in `evaluate_method'",
"state_machines (0.5.0) lib/state_machines/callback.rb:192:in `block in run_methods'",
"state_machines (0.5.0) lib/state_machines/callback.rb:191:in `each'",
"state_machines (0.5.0) lib/state_machines/callback.rb:191:in `run_methods'",
"state_machines (0.5.0) lib/state_machines/callback.rb:159:in `call'",
"state_machines (0.5.0) lib/state_machines/transition.rb:394:in `block (2 levels) in after'",
"state_machines (0.5.0) lib/state_machines/transition.rb:394:in `each'",
"state_machines (0.5.0) lib/state_machines/transition.rb:394:in `block in after'",
"state_machines (0.5.0) lib/state_machines/transition.rb:392:in `catch'",
"state_machines (0.5.0) lib/state_machines/transition.rb:392:in `after'",
"state_machines (0.5.0) lib/state_machines/transition.rb:195:in `run_callbacks'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:127:in `run_callbacks'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:212:in `run_callbacks'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:63:in `block (2 levels) in perform'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:63:in `catch'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:63:in `block in perform'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:182:in `block in within_transaction'",
"state_machines (0.5.0) lib/state_machines/transition.rb:171:in `block in within_transaction'",
"state_machines (0.5.0) lib/state_machines/machine.rb:1868:in `block in within_transaction'",
"state_machines-activerecord (0.8.0) lib/state_machines/integrations/active_record.rb:557:in `block in transaction'",
"app/models/concerns/cross_database_modification.rb:92:in `block in transaction'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'",
"activesupport (7.0.8.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'",
"activesupport (7.0.8.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'",
"activesupport (7.0.8.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'",
"activesupport (7.0.8.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/abstract/transaction.rb:317:in `within_new_transaction'",
"activerecord (7.0.8.4) lib/active_record/connection_adapters/abstract/database_statements.rb:316:in `transaction'",
"lib/gitlab/database/load_balancing/connection_proxy.rb:127:in `public_send'",
"lib/gitlab/database/load_balancing/connection_proxy.rb:127:in `block in write_using_load_balancer'",
"lib/gitlab/database/load_balancing/load_balancer.rb:141:in `block in read_write'",
"lib/gitlab/database/load_balancing/load_balancer.rb:228:in `retry_with_backoff'",
"lib/gitlab/database/load_balancing/load_balancer.rb:130:in `read_write'",
"lib/gitlab/database/load_balancing/connection_proxy.rb:126:in `write_using_load_balancer'",
"lib/gitlab/database/load_balancing/connection_proxy.rb:78:in `transaction'",
"activerecord (7.0.8.4) lib/active_record/transactions.rb:209:in `transaction'",
"lib/gitlab/database.rb:359:in `block in transaction'",
"activesupport (7.0.8.4) lib/active_support/notifications.rb:206:in `block in instrument'",
"activesupport (7.0.8.4) lib/active_support/notifications/instrumenter.rb:24:in `instrument'",
"activesupport (7.0.8.4) lib/active_support/notifications.rb:206:in `instrument'",
"lib/gitlab/database.rb:358:in `transaction'",
"app/models/concerns/cross_database_modification.rb:83:in `transaction'",
"state_machines-activerecord (0.8.0) lib/state_machines/integrations/active_record.rb:556:in `transaction'",
"state_machines (0.5.0) lib/state_machines/machine.rb:1868:in `within_transaction'",
"state_machines (0.5.0) lib/state_machines/transition.rb:170:in `within_transaction'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:181:in `within_transaction'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:62:in `perform'",
"state_machines-activerecord (0.8.0) lib/state_machines/integrations/active_record.rb:530:in `around_save'",
"state_machines-activerecord (0.8.0) lib/state_machines/integrations/active_record.rb:511:in `save'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:154:in `block (2 levels) in run_actions'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:154:in `each'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:154:in `block in run_actions'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:170:in `catch_exceptions'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:148:in `run_actions'",
"state_machines (0.5.0) lib/state_machines/transition_collection.rb:60:in `perform'",
"state_machines (0.5.0) lib/state_machines/transition.rb:163:in `perform'",
"state_machines (0.5.0) lib/state_machines/event.rb:155:in `fire'",
"state_machines (0.5.0) lib/state_machines/event.rb:219:in `block in add_actions'",
"state_machines (0.5.0) lib/state_machines/machine.rb:729:in `block (2 levels) in define_helper'",
"ee/lib/ee/gitlab/auth/saml/user.rb:43:in `block_user'",
"ee/lib/ee/gitlab/auth/saml/user.rb:17:in `find_user'",
"lib/gitlab/auth/o_auth/user.rb:77:in `gl_user'",
"lib/gitlab/auth/o_auth/user.rb:263:in `update_profile'",
"lib/gitlab/auth/o_auth/user.rb:34:in `initialize'",
"app/controllers/omniauth_callbacks_controller.rb:203:in `new'",
"app/controllers/omniauth_callbacks_controller.rb:203:in `block in build_auth_user'",
"gems/gitlab-utils/lib/gitlab/utils/strong_memoize.rb:65:in `strong_memoize_with'",
"app/controllers/omniauth_callbacks_controller.rb:202:in `build_auth_user'",
"app/controllers/omniauth_callbacks_controller.rb:155:in `omniauth_flow'",
"app/controllers/omniauth_callbacks_controller.rb:75:in `saml'",
"actionpack (7.0.8.4) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'",
"actionpack (7.0.8.4) lib/abstract_controller/base.rb:215:in `process_action'",
"actionpack (7.0.8.4) lib/action_controller/metal/rendering.rb:165:in `process_action'",
"actionpack (7.0.8.4) lib/abstract_controller/callbacks.rb:234:in `block in process_action'",
"activesupport (7.0.8.4) lib/active_support/callbacks.rb:118:in `block in run_callbacks'",
"lib/gitlab/ip_address_state.rb:11:in `with'",
"ee/app/controllers/ee/application_controller.rb:45:in `set_current_ip_address'",
"activesupport (7.0.8.4) lib/active_support/callbacks.rb:127:in `block in run_callbacks'",
"app/controllers/application_controller.rb:474:in `set_current_admin'",
"activesupport (7.0.8.4) lib/active_support/callbacks.rb:127:in `block in run_callbacks'",
"lib/gitlab/session.rb:11:in `with_session'",
"app/controllers/application_controller.rb:465:in `set_session_storage'",
"activesupport (7.0.8.4) lib/active_support/callbacks.rb:127:in `block in run_callbacks'",
"lib/gitlab/i18n.rb:114:in `with_locale'",
"lib/gitlab/i18n.rb:120:in `with_user_locale'",
"app/controllers/application_controller.rb:456:in `set_locale'",
"activesupport (7.0.8.4) lib/active_support/callbacks.rb:127:in `block in run_callbacks'",
"marginalia (1.11.1) lib/marginalia.rb:109:in `record_query_comment'",
"activesupport (7.0.8.4) lib/active_support/callbacks.rb:127:in `block in run_callbacks'",
"app/controllers/application_controller.rb:449:in `set_current_context'",
"activesupport (7.0.8.4) lib/active_support/callbacks.rb:127:in `block in run_callbacks'",
"sentry-rails (5.18.2) lib/sentry/rails/controller_transaction.rb:30:in `block in sentry_around_action'",
"sentry-ruby (5.18.2) lib/sentry/hub.rb:102:in `with_child_span'",
"sentry-ruby (5.18.2) lib/sentry-ruby.rb:491:in `with_child_span'",
"sentry-rails (5.18.2) lib/sentry/rails/controller_transaction.rb:16:in `sentry_around_action'",
"activesupport (7.0.8.4) lib/active_support/callbacks.rb:127:in `block in run_callbacks'",
"activesupport (7.0.8.4) lib/active_support/callbacks.rb:138:in `run_callbacks'",
"actionpack (7.0.8.4) lib/abstract_controller/callbacks.rb:233:in `process_action'",
"actionpack (7.0.8.4) lib/action_controller/metal/rescue.rb:23:in `process_action'",
"actionpack (7.0.8.4) lib/action_controller/metal/instrumentation.rb:67:in `block in process_action'",
"activesupport (7.0.8.4) lib/active_support/notifications.rb:206:in `block in instrument'",
"activesupport (7.0.8.4) lib/active_support/notifications/instrumenter.rb:24:in `instrument'",
"activesupport (7.0.8.4) lib/active_support/notifications.rb:206:in `instrument'",
"actionpack (7.0.8.4) lib/action_controller/metal/instrumentation.rb:66:in `process_action'",
"actionpack (7.0.8.4) lib/action_controller/metal/params_wrapper.rb:259:in `process_action'",
"activerecord (7.0.8.4) lib/active_record/railties/controller_runtime.rb:27:in `process_action'",
"actionpack (7.0.8.4) lib/abstract_controller/base.rb:151:in `process'",
"actionview (7.0.8.4) lib/action_view/rendering.rb:39:in `process'",
"actionpack (7.0.8.4) lib/action_controller/metal.rb:188:in `dispatch'",
"actionpack (7.0.8.4) lib/action_controller/metal.rb:251:in `dispatch'",
"actionpack (7.0.8.4) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'",
"actionpack (7.0.8.4) lib/action_dispatch/routing/route_set.rb:32:in `serve'",
"actionpack (7.0.8.4) lib/action_dispatch/routing/mapper.rb:18:in `block in <class:Constraints>'",
"actionpack (7.0.8.4) lib/action_dispatch/routing/mapper.rb:48:in `serve'",
"actionpack (7.0.8.4) lib/action_dispatch/journey/router.rb:50:in `block in serve'",
"actionpack (7.0.8.4) lib/action_dispatch/journey/router.rb:32:in `each'",
"actionpack (7.0.8.4) lib/action_dispatch/journey/router.rb:32:in `serve'",
"actionpack (7.0.8.4) lib/action_dispatch/routing/route_set.rb:852:in `call'",
"gitlab-experiment (0.9.1) lib/gitlab/experiment/middleware.rb:19:in `call'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:202:in `call!'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:169:in `call'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:470:in `call_app!'",
"omniauth_openid_connect (0.8.0) lib/omniauth/strategies/openid_connect.rb:163:in `other_phase'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:195:in `call!'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:169:in `call'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:470:in `call_app!'",
"omniauth-saml (2.1.0) lib/omniauth/strategies/saml.rb:86:in `other_phase'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:195:in `call!'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:169:in `call'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:470:in `call_app!'",
"omniauth-saml (2.1.0) lib/omniauth/strategies/saml.rb:86:in `other_phase'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:195:in `call!'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:169:in `call'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:470:in `call_app!'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:418:in `callback_phase'",
"omniauth-saml (2.1.0) lib/omniauth/strategies/saml.rb:50:in `block (2 levels) in callback_phase'",
"omniauth-saml (2.1.0) lib/omniauth/strategies/saml.rb:144:in `handle_response'",
"omniauth-saml (2.1.0) lib/omniauth/strategies/saml.rb:49:in `block in callback_phase'",
"omniauth-saml (2.1.0) lib/omniauth/strategies/saml.rb:218:in `with_settings'",
"omniauth-saml (2.1.0) lib/omniauth/strategies/saml.rb:45:in `callback_phase'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:272:in `callback_call'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:194:in `call!'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:169:in `call'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:470:in `call_app!'",
"ee/lib/omni_auth/strategies/group_saml.rb:41:in `other_phase'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:195:in `call!'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:169:in `call'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:202:in `call!'",
"omniauth (2.1.0) lib/omniauth/strategy.rb:169:in `call'",
"flipper (0.26.2) lib/flipper/middleware/memoizer.rb:72:in `memoized_call'",
"flipper (0.26.2) lib/flipper/middleware/memoizer.rb:37:in `call'",
"lib/gitlab/metrics/elasticsearch_rack_middleware.rb:16:in `call'",
"lib/gitlab/middleware/sidekiq_shard_awareness_validation.rb:20:in `block in call'",
"lib/gitlab/sidekiq_sharding/validator.rb:42:in `enabled'",
"lib/gitlab/middleware/sidekiq_shard_awareness_validation.rb:20:in `call'",
"lib/gitlab/middleware/memory_report.rb:13:in `call'",
"lib/gitlab/middleware/speedscope.rb:13:in `call'",
"lib/gitlab/database/load_balancing/rack_middleware.rb:23:in `call'",
"lib/gitlab/middleware/rails_queue_duration.rb:33:in `call'",
"lib/gitlab/etag_caching/middleware.rb:21:in `call'",
"lib/gitlab/metrics/rack_middleware.rb:16:in `block in call'",
"lib/gitlab/metrics/web_transaction.rb:46:in `run'",
"lib/gitlab/metrics/rack_middleware.rb:16:in `call'",
"lib/gitlab/middleware/go.rb:24:in `call'",
"lib/gitlab/middleware/query_analyzer.rb:11:in `block in call'",
"lib/gitlab/database/query_analyzer.rb:40:in `within'",
"lib/gitlab/middleware/query_analyzer.rb:11:in `call'",
"batch-loader (2.0.5) lib/batch_loader/middleware.rb:11:in `call'",
"rack-attack (6.7.0) lib/rack/attack.rb:103:in `call'",
"apollo_upload_server (2.1.6) lib/apollo_upload_server/middleware.rb:19:in `call'",
"lib/gitlab/middleware/multipart.rb:173:in `call'",
"rack-attack (6.7.0) lib/rack/attack.rb:127:in `call'",
"warden (1.2.9) lib/warden/manager.rb:36:in `block in call'",
"warden (1.2.9) lib/warden/manager.rb:34:in `catch'",
"warden (1.2.9) lib/warden/manager.rb:34:in `call'",
"rack-cors (2.0.2) lib/rack/cors.rb:102:in `call'",
"rack (2.2.9) lib/rack/tempfile_reaper.rb:15:in `call'",
"rack (2.2.9) lib/rack/etag.rb:27:in `call'",
"rack (2.2.9) lib/rack/conditional_get.rb:40:in `call'",
"rack (2.2.9) lib/rack/head.rb:12:in `call'",
"actionpack (7.0.8.4) lib/action_dispatch/http/permissions_policy.rb:38:in `call'",
"actionpack (7.0.8.4) lib/action_dispatch/http/content_security_policy.rb:36:in `call'",
"lib/gitlab/middleware/read_only/controller.rb:50:in `call'",
"lib/gitlab/middleware/read_only.rb:18:in `call'",
"lib/gitlab/middleware/unauthenticated_session_expiry.rb:18:in `call'",
"rack (2.2.9) lib/rack/session/abstract/id.rb:266:in `context'",
"rack (2.2.9) lib/rack/session/abstract/id.rb:260:in `call'",
"actionpack (7.0.8.4) lib/action_dispatch/middleware/cookies.rb:704:in `call'",
"lib/gitlab/middleware/same_site_cookies.rb:27:in `call'",
"actionpack (7.0.8.4) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'",
"activesupport (7.0.8.4) lib/active_support/callbacks.rb:99:in `run_callbacks'",
"actionpack (7.0.8.4) lib/action_dispatch/middleware/callbacks.rb:26:in `call'",
"sentry-rails (5.18.2) lib/sentry/rails/rescued_exception_interceptor.rb:12:in `call'",
"actionpack (7.0.8.4) lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'",
"lib/gitlab/middleware/path_traversal_check.rb:27:in `call'",
"lib/gitlab/middleware/handle_malformed_strings.rb:21:in `call'",
"sentry-ruby (5.18.2) lib/sentry/rack/capture_exceptions.rb:30:in `block (2 levels) in call'",
"sentry-ruby (5.18.2) lib/sentry/hub.rb:258:in `with_session_tracking'",
"sentry-ruby (5.18.2) lib/sentry-ruby.rb:404:in `with_session_tracking'",
"sentry-ruby (5.18.2) lib/sentry/rack/capture_exceptions.rb:21:in `block in call'",
"sentry-ruby (5.18.2) lib/sentry/hub.rb:59:in `with_scope'",
"sentry-ruby (5.18.2) lib/sentry-ruby.rb:384:in `with_scope'",
"sentry-ruby (5.18.2) lib/sentry/rack/capture_exceptions.rb:20:in `call'",
"actionpack (7.0.8.4) lib/action_dispatch/middleware/show_exceptions.rb:29:in `call'",
"lib/gitlab/middleware/basic_health_check.rb:25:in `call'",
"lograge (0.11.2) lib/lograge/rails_ext/rack/logger.rb:15:in `call_app'",
"railties (7.0.8.4) lib/rails/rack/logger.rb:25:in `block in call'",
"activesupport (7.0.8.4) lib/active_support/tagged_logging.rb:99:in `block in tagged'",
"activesupport (7.0.8.4) lib/active_support/tagged_logging.rb:37:in `tagged'",
"activesupport (7.0.8.4) lib/active_support/tagged_logging.rb:99:in `tagged'",
"railties (7.0.8.4) lib/rails/rack/logger.rb:25:in `call'",
"actionpack (7.0.8.4) lib/action_dispatch/middleware/remote_ip.rb:93:in `call'",
"lib/gitlab/middleware/handle_ip_spoof_attack_error.rb:25:in `call'",
"lib/gitlab/middleware/request_context.rb:15:in `call'",
"lib/gitlab/middleware/webhook_recursion_detection.rb:15:in `call'",
"request_store (1.5.1) lib/request_store/middleware.rb:19:in `call'",
"rack (2.2.9) lib/rack/method_override.rb:24:in `call'",
"rack (2.2.9) lib/rack/runtime.rb:22:in `call'",
"rack-timeout (0.7.0) lib/rack/timeout/core.rb:154:in `block in call'",
"rack-timeout (0.7.0) lib/rack/timeout/support/timeout.rb:19:in `timeout'",
"rack-timeout (0.7.0) lib/rack/timeout/core.rb:153:in `call'",
"config/initializers/fix_local_cache_middleware.rb:11:in `call'",
"lib/gitlab/middleware/compressed_json.rb:44:in `call'",
"actionpack (7.0.8.4) lib/action_dispatch/middleware/executor.rb:14:in `call'",
"lib/gitlab/middleware/rack_multipart_tempfile_factory.rb:19:in `call'",
"rack (2.2.9) lib/rack/sendfile.rb:110:in `call'",
"lib/gitlab/middleware/sidekiq_web_static.rb:20:in `call'",
"lib/gitlab/metrics/requests_rack_middleware.rb:79:in `call'",
"gitlab-labkit (0.36.1) lib/labkit/middleware/rack.rb:22:in `block in call'",
"gitlab-labkit (0.36.1) lib/labkit/context.rb:35:in `with_context'",
"gitlab-labkit (0.36.1) lib/labkit/middleware/rack.rb:21:in `call'",
"actionpack (7.0.8.4) lib/action_dispatch/middleware/request_id.rb:26:in `call'",
"actionpack (7.0.8.4) lib/action_dispatch/middleware/host_authorization.rb:131:in `call'",
"railties (7.0.8.4) lib/rails/engine.rb:530:in `call'",
"railties (7.0.8.4) lib/rails/railtie.rb:226:in `public_send'",
"railties (7.0.8.4) lib/rails/railtie.rb:226:in `method_missing'",
"lib/gitlab/middleware/release_env.rb:13:in `call'",
"rack (2.2.9) lib/rack/urlmap.rb:74:in `block in call'",
"rack (2.2.9) lib/rack/urlmap.rb:58:in `each'",
"rack (2.2.9) lib/rack/urlmap.rb:58:in `call'",
"puma (6.4.0) lib/puma/configuration.rb:272:in `call'",
"puma (6.4.0) lib/puma/request.rb:100:in `block in handle_request'",
"puma (6.4.0) lib/puma/thread_pool.rb:378:in `with_force_shutdown'",
"puma (6.4.0) lib/puma/request.rb:99:in `handle_request'",
"puma (6.4.0) lib/puma/server.rb:443:in `process_client'",
"puma (6.4.0) lib/puma/server.rb:241:in `block in run'",
"puma (6.4.0) lib/puma/thread_pool.rb:155:in `block in spawn_thread'"
],
"exception.cause_class": "PG::CheckViolation",
"exception.sql": "/*application:web,correlation_id:01J7HCEB4XYY225PMRSTYRSQ9Y,endpoint_id:OmniauthCallbacksController#saml,db_config_name:main*/ UPDATE \"projects\" SET \"star_count\" = COALESCE(\"star_count\", $1) - $2 WHERE \"projects\".\"id\" IN (SELECT \"projects\".\"id\" FROM \"projects\" INNER JOIN \"users_star_projects\" ON \"projects\".\"id\" = \"users_star_projects\".\"project_id\" WHERE \"users_star_projects\".\"user_id\" = $3)",
"db_duration_s": 0.04401,
"view_duration_s": 0.0,
"duration_s": 0.1941
}
Possible fixes
- https://gitlab.com/gitlab-org/gitlab/-/blob/771f08c2cb9cb5b6216ef2fb76f84de2f496659f/app/models/user.rb#L584
- https://gitlab.com/gitlab-org/gitlab/-/blob/771f08c2cb9cb5b6216ef2fb76f84de2f496659f/app/models/users_star_project.rb#L49-51
Workaround
Updates projects that have a mismatch with a star_count equal to the active users who have starred the project. Allows project star data to be accurate if blocked users are ever re-activated.
Project.find_each(batch_size: 100) do |p|
starrers_count = p.starrers.count
starrers_active_count = p.starrers.active.count
if starrers_count != p.star_count
puts "#{p.id}, #{p.full_path}, #{starrers_count}, #{starrers_active_count}, #{p.star_count}"
p.update(star_count: starrers_active_count)
end
end; nil