PG::UniqueViolation error when updating group push rules on specific groups
Summary:
GitLab Dedicated customer experiencing 500 errors when attempting to update existing group push rules via UI or API on a specific group. The error indicates the application is attempting to INSERT new records instead of UPDATE existing ones, with incrementing primary key conflicts. New groups are unaffected. Issue is not reproducible on test instances.
GitLab Version: 18.7.2 (GitLab Dedicated)
Steps taken by customer:
- Navigate to an affected group with existing push rules configured
- Go to Settings > Repository > Push Rules (path:
/groups/{group_path}/-/push_rules) - Modify any push rule setting
- Click "Save push rules"
- Observe 500 error
Note: Issue is specific to certain groups. New groups can create and update push rules successfully. Not reproducible on test instance (https://dedicatedtestsandbox.gitlab-private.org).
Expected Behavior:
Existing group push rules should be updated successfully via UPDATE query.
Actual Behavior:
- 500 error returned to user
- Application attempts INSERT instead of UPDATE on
group_push_rulestable -
PG::UniqueViolationerror: duplicate key value violates unique constraint "group_push_rules_pkey" - Each retry attempt increments the conflicting ID (56, 57, 58, 60, 61, 62, 63, 66...)
Error Details:
"exception.message": "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "group_push_rules_pkey"
DETAIL: Key (id)=(63) already exists.",
"exception.cause_class": "PG::UniqueViolation",
"exception.sql": "INSERT INTO \"group_push_rules\" (\"created_at\", \"updated_at\", \"group_id\", \"prevent_secrets\", \"deny_delete_tag\", \"reject_unsigned_commits\", \"commit_committer_check\", \"reject_non_dco_commits\", \"commit_message_regex\", \"branch_name_regex\", \"commit_message_negative_regex\", \"author_email_regex\", \"file_name_regex\") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING \"id\"",
"controller": "Groups::PushRulesController",
"action": "update",
"status": 500,
"path": "/groups/[REDACTED]/-/push_rules",
"method": "PUT"
Sample error progression showing incrementing IDs:
- Feb 2, 2026 @ 06:27:26 - Key (id)=(56) already exists
- Feb 2, 2026 @ 06:27:30 - Key (id)=(57) already exists
- Feb 2, 2026 @ 06:34:26 - Key (id)=(58) already exists
- Feb 2, 2026 @ 06:36:27 - Key (id)=(60) already exists
- Feb 4, 2026 @ 03:13:34 - Key (id)=(66) already exists
Error stack trace:
Click to expand
activerecord (7.2.3) lib/active_record/connection_adapters/postgresql_adapter.rb:899:in `exec_params',
activerecord (7.2.3) lib/active_record/connection_adapters/postgresql_adapter.rb:899:in `block (2 levels) in exec_no_cache',
activerecord (7.2.3) lib/active_record/connection_adapters/abstract_adapter.rb:1024:in `block in with_raw_connection',
activesupport (7.2.3) lib/active_support/concurrency/null_lock.rb:9:in `synchronize',
activerecord (7.2.3) lib/active_record/connection_adapters/abstract_adapter.rb:993:in `with_raw_connection',
activerecord (7.2.3) lib/active_record/connection_adapters/postgresql_adapter.rb:898:in `block in exec_no_cache',
activesupport (7.2.3) lib/active_support/notifications/instrumenter.rb:58:in `instrument',
activerecord (7.2.3) lib/active_record/connection_adapters/abstract_adapter.rb:1141:in `log',
activerecord (7.2.3) lib/active_record/connection_adapters/postgresql_adapter.rb:897:in `exec_no_cache',
activerecord (7.2.3) lib/active_record/connection_adapters/postgresql_adapter.rb:877:in `execute_and_clear',
marginalia (1.11.1) lib/marginalia.rb:91:in `execute_and_clear_with_marginalia',
activerecord (7.2.3) lib/active_record/connection_adapters/postgresql/database_statements.rb:66:in `internal_exec_query',
activerecord (7.2.3) lib/active_record/connection_adapters/abstract/database_statements.rb:159:in `exec_insert',
activerecord (7.2.3) lib/active_record/connection_adapters/postgresql/database_statements.rb:85:in `exec_insert',
activerecord (7.2.3) lib/active_record/connection_adapters/abstract/database_statements.rb:197:in `insert',
activerecord (7.2.3) lib/active_record/connection_adapters/abstract/query_cache.rb:27:in `insert',
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:229:in `retry_with_backoff',
lib/gitlab/database/load_balancing/load_balancer.rb:131: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.2.3) lib/active_record/persistence.rb:258:in `block in _insert_record',
lib/gitlab/database/load_balancing/setup.rb:57:in `block in setup_connection_proxy',
activerecord (7.2.3) lib/active_record/persistence.rb:251:in `_insert_record',
activerecord (7.2.3) lib/active_record/persistence.rb:928:in `block in _create_record',
lib/gitlab/database/load_balancing/setup.rb:57:in `block in setup_connection_proxy',
activerecord (7.2.3) lib/active_record/persistence.rb:925:in `_create_record',
activerecord (7.2.3) lib/active_record/counter_cache.rb:201:in `_create_record',
activerecord (7.2.3) lib/active_record/locking/optimistic.rb:84:in `_create_record',
activerecord (7.2.3) lib/active_record/encryption/encryptable_record.rb:184:in `_create_record',
activerecord (7.2.3) lib/active_record/attribute_methods/dirty.rb:240:in `_create_record',
activerecord (7.2.3) lib/active_record/callbacks.rb:445:in `block in _create_record',
activesupport (7.2.3) lib/active_support/callbacks.rb:101:in `run_callbacks',
activesupport (7.2.3) lib/active_support/callbacks.rb:914:in `_run_create_callbacks',
activerecord (7.2.3) lib/active_record/callbacks.rb:445:in `_create_record',
activerecord (7.2.3) lib/active_record/timestamp.rb:116:in `_create_record',
activerecord (7.2.3) lib/active_record/persistence.rb:896:in `create_or_update',
activerecord (7.2.3) lib/active_record/callbacks.rb:441:in `block in create_or_update',
activesupport (7.2.3) lib/active_support/callbacks.rb:110:in `run_callbacks',
activesupport (7.2.3) lib/active_support/callbacks.rb:914:in `_run_save_callbacks',
activerecord (7.2.3) lib/active_record/callbacks.rb:441:in `create_or_update',
activerecord (7.2.3) lib/active_record/timestamp.rb:127:in `create_or_update',
activerecord (7.2.3) lib/active_record/persistence.rb:393:in `save',
activerecord (7.2.3) lib/active_record/validations.rb:48:in `save',
activerecord (7.2.3) lib/active_record/transactions.rb:362:in `block in save',
activerecord (7.2.3) lib/active_record/transactions.rb:418:in `block (2 levels) in with_transaction_returning_status',
activerecord (7.2.3) lib/active_record/connection_adapters/abstract/database_statements.rb:359: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:229:in `retry_with_backoff',
lib/gitlab/database/load_balancing/load_balancer.rb:131: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.2.3) lib/active_record/transactions.rb:414:in `block in with_transaction_returning_status',
lib/gitlab/database/load_balancing/setup.rb:57:in `block in setup_connection_proxy',
activerecord (7.2.3) lib/active_record/transactions.rb:410:in `with_transaction_returning_status',
activerecord (7.2.3) lib/active_record/transactions.rb:362:in `save',
activerecord (7.2.3) lib/active_record/suppressor.rb:52:in `save',
activerecord (7.2.3) lib/active_record/persistence.rb:570:in `block in update',
activerecord (7.2.3) lib/active_record/transactions.rb:418:in `block (2 levels) in with_transaction_returning_status',
activerecord (7.2.3) lib/active_record/connection_adapters/abstract/transaction.rb:616:in `block in within_new_transaction',
activesupport (7.2.3) lib/active_support/concurrency/null_lock.rb:9:in `synchronize',
activerecord (7.2.3) lib/active_record/connection_adapters/abstract/transaction.rb:613:in `within_new_transaction',
activerecord (7.2.3) lib/active_record/connection_adapters/abstract/database_statements.rb:361: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:229:in `retry_with_backoff',
lib/gitlab/database/load_balancing/load_balancer.rb:131: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.2.3) lib/active_record/transactions.rb:414:in `block in with_transaction_returning_status',
lib/gitlab/database/load_balancing/setup.rb:57:in `block in setup_connection_proxy',
activerecord (7.2.3) lib/active_record/transactions.rb:410:in `with_transaction_returning_status',
activerecord (7.2.3) lib/active_record/persistence.rb:568:in `update',
ee/app/services/push_rules/create_or_update_service.rb:18:in `execute',
ee/app/controllers/groups/push_rules_controller.rb:19:in `update',
actionpack (7.2.3) lib/action_controller/metal/basic_implicit_render.rb:8:in `send_action',
actionpack (7.2.3) lib/abstract_controller/base.rb:215:in `process_action',
actionpack (7.2.3) lib/action_controller/metal/rendering.rb:193:in `process_action',
actionpack (7.2.3) lib/abstract_controller/callbacks.rb:261:in `block in process_action',
activesupport (7.2.3) lib/active_support/callbacks.rb:121:in `block in run_callbacks',
app/controllers/application_controller.rb:497:in `set_current_admin',
activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks',
lib/gitlab/session.rb:11:in `with_session',
app/controllers/application_controller.rb:488:in `set_session_storage',
activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks',
lib/gitlab/i18n.rb:116:in `with_locale',
lib/gitlab/i18n.rb:122:in `with_user_locale',
app/controllers/application_controller.rb:479:in `set_locale',
activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks',
app/controllers/application_controller.rb:468:in `set_current_context',
activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks',
lib/gitlab/ip_address_state.rb:11:in `with',
app/controllers/application_controller.rb:474:in `set_current_ip_address',
activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks',
marginalia (1.11.1) lib/marginalia.rb:109:in `record_query_comment',
activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks',
sentry-rails (5.23.0) lib/sentry/rails/controller_transaction.rb:34:in `block in sentry_around_action',
sentry-ruby (5.23.0) lib/sentry/hub.rb:138:in `with_child_span',
sentry-ruby (5.23.0) lib/sentry-ruby.rb:515:in `with_child_span',
sentry-rails (5.23.0) lib/sentry/rails/controller_transaction.rb:18:in `sentry_around_action',
activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks',
activesupport (7.2.3) lib/active_support/callbacks.rb:141:in `run_callbacks',
actionpack (7.2.3) lib/abstract_controller/callbacks.rb:260:in `process_action',
actionpack (7.2.3) lib/action_controller/metal/rescue.rb:27:in `process_action',
actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:77:in `block in process_action',
activesupport (7.2.3) lib/active_support/notifications.rb:210:in `block in instrument',
activesupport (7.2.3) lib/active_support/notifications/instrumenter.rb:58:in `instrument',
activesupport (7.2.3) lib/active_support/notifications.rb:210:in `instrument',
actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:76:in `process_action',
actionpack (7.2.3) lib/action_controller/metal/params_wrapper.rb:259:in `process_action',
activerecord (7.2.3) lib/active_record/railties/controller_runtime.rb:39:in `process_action',
actionpack (7.2.3) lib/abstract_controller/base.rb:152:in `process',
actionview (7.2.3) lib/action_view/rendering.rb:40:in `process',
actionpack (7.2.3) lib/action_controller/metal.rb:252:in `dispatch',
actionpack (7.2.3) lib/action_controller/metal.rb:333:in `block in dispatch',
lib/gitlab/middleware/action_controller_static_context.rb:23:in `call',
actionpack (7.2.3) lib/action_controller/metal.rb:333:in `dispatch',
actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:67:in `dispatch',
actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:50:in `serve',
actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:32:in `block in <class:Constraints>',
actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:62:in `serve',
actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve',
config/initializers/action_dispatch_journey_router.rb:52:in `block in find_routes',
config/initializers/action_dispatch_journey_router.rb:25:in `map!',
config/initializers/action_dispatch_journey_router.rb:25:in `find_routes',
actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve',
actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call',
gitlab-experiment (1.1.0) lib/gitlab/experiment/middleware.rb:19:in `call',
omniauth (2.1.4) lib/omniauth/strategy.rb:478:in `call_app!',
omniauth-saml (2.2.4) lib/omniauth/strategies/saml.rb:83:in `other_phase',
omniauth (2.1.4) lib/omniauth/strategy.rb:195:in `call!',
omniauth (2.1.4) lib/omniauth/strategy.rb:169:in `call',
flipper (0.28.3) lib/flipper/middleware/memoizer.rb:72:in `memoized_call',
flipper (0.28.3) 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/middlewa
re/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:21:in `call',
lib/gitlab/middleware/query_analyzer.rb:11:in `block in call',
lib/gitlab/database/query_analyzer.rb:94:in `within',
lib/gitlab/middleware/query_analyzer.rb:11:in `call',
lib/ci/job_token/middleware.rb:11:in `call',
batch-loader (2.0.5) lib/batch_loader/middleware.rb:11:in `call',
rack-attack (6.8.0) lib/rack/attack.rb:105:in `call',
apollo_upload_server (2.1.6) lib/apollo_upload_server/middleware.rb:19:in `call',
lib/gitlab/middleware/multipart.rb:177:in `call',
lib/gitlab/middleware/rack_attack_headers.rb:42:in `call',
rack-attack (6.8.0) lib/rack/attack.rb:129: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.21) lib/rack/tempfile_reaper.rb:15:in `call',
rack (2.2.21) lib/rack/etag.rb:27:in `call',
rack (2.2.21) lib/rack/conditional_get.rb:40:in `call',
rack (2.2.21) lib/rack/head.rb:12:in `call',
actionpack (7.2.3) lib/action_dispatch/http/permissions_policy.rb:38:in `call',
actionpack (7.2.3) lib/action_dispatch/http/content_security_policy.rb:38:in `call',
lib/gitlab/middleware/read_only/controller.rb:40:in `call',
lib/gitlab/middleware/read_only.rb:18:in `call',
lib/gitlab/middleware/unauthenticated_session_expiry.rb:18:in `call',
rack (2.2.21) lib/rack/session/abstract/id.rb:266:in `context',
rack (2.2.21) lib/rack/session/abstract/id.rb:260:in `call',
lib/gitlab/middleware/secure_headers.rb:11:in `call',
actionpack (7.2.3) lib/action_dispatch/middleware/cookies.rb:704:in `call',
lib/gitlab/middleware/same_site_cookies.rb:27:in `call',
actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call',
activesupport (7.2.3) lib/active_support/callbacks.rb:101:in `run_callbacks',
actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:30:in `call',
sentry-rails (5.23.0) lib/sentry/rails/rescued_exception_interceptor.rb:14:in `call',
actionpack (7.2.3) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call',
lib/gitlab/middleware/path_traversal_check.rb:40:in `call',
lib/gitlab/middleware/handle_malformed_strings.rb:19:in `call',
lib/gitlab/middleware/json_validation.rb:165:in `call',
sentry-ruby (5.23.0) lib/sentry/rack/capture_exceptions.rb:30:in `block (2 levels) in call',
sentry-ruby (5.23.0) lib/sentry/hub.rb:299:in `with_session_tracking',
sentry-ruby (5.23.0) lib/sentry-ruby.rb:428:in `with_session_tracking',
sentry-ruby (5.23.0) lib/sentry/rack/capture_exceptions.rb:21:in `block in call',
sentry-ruby (5.23.0) lib/sentry/hub.rb:89:in `with_scope',
sentry-ruby (5.23.0) lib/sentry-ruby.rb:408:in `with_scope',
sentry-ruby (5.23.0) lib/sentry/rack/capture_exceptions.rb:20:in `call',
actionpack (7.2.3) lib/action_dispatch/middleware/show_exceptions.rb:32: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.2.3) lib/rails/rack/logger.rb:29:in `call',
actionpack (7.2.3) lib/action_dispatch/middleware/remote_ip.rb:96: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.7.0) lib/request_store/middleware.rb:19:in `call',
rack (2.2.21) lib/rack/method_override.rb:24:in `call',
rack (2.2.21) 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.2.3) lib/action_dispatch/middleware/executor.rb:16:in `call',
lib/gitlab/middleware/rack_multipart_tempfile_factory.rb:19:in `call',
rack (2.2.21) lib/rack/sendfile.rb:127:in `call',
lib/gitlab/metrics/requests_rack_middleware.rb:83:in `call',
gitlab-labkit (1.0.1) lib/labkit/middleware/rack.rb:22:in `block in call',
gitlab-labkit (1.0.1) lib/labkit/context.rb:43:in `with_context',
gitlab-labkit (1.0.1) lib/labkit/middleware/rack.rb:21:in `call',
actionpack (7.2.3) lib/action_dispatch/middleware/request_id.rb:33:in `call',
lib/gitlab/middleware/static_assets_authorization.rb:23:in `call',
railties (7.2.3) lib/rails/engine.rb:535:in `call',
railties (7.2.3) lib/rails/railtie.rb:226:in `public_send',
railties (7.2.3) lib/rails/railtie.rb:226:in `method_missing',
lib/gitlab/middleware/release_env.rb:12:in `call',
rack (2.2.21) lib/rack/urlmap.rb:74:in `block in call',
rack (2.2.21) lib/rack/urlmap.rb:58:in `each',
rack (2.2.21) lib/rack/urlmap.rb:58:in `call',
puma (7.1.0) lib/puma/configuration.rb:300:in `call',
puma (7.1.0) lib/puma/request.rb:101:in `block in handle_request',
puma (7.1.0) lib/puma/thread_pool.rb:355:in `with_force_shutdown',
puma (7.1.0) lib/puma/request.rb:100:in `handle_request',
puma (7.1.0) lib/puma/server.rb:503:in `process_client',
puma (7.1.0) lib/puma/server.rb:262:in `block in run',
puma (7.1.0) lib/puma/thread_pool.rb:182:in `block in spawn_thread'
Impact:
- Users cannot update group push rules on affected groups
- Issue affects both UI and API endpoints
- Currently one customer group confirmed affected
- New groups are unaffected (can create and update push rules successfully)
- Not reproducible on test instances, suggesting environment-specific or data-specific issue
Possible Causes:
The Groups::PushRulesController#update action is incorrectly attempting to INSERT rather than UPDATE. Potential causes include:
- The controller is not finding the existing
group_push_rulesrecord for affected groups - The record lookup is failing due to data inconsistency
- Database sequence for
group_push_rules_id_seqis desynchronized with actual table data - Corrupted or orphaned data in the affected group's push rules association
Relevant Code:
Controller: app/controllers/groups/push_rules_controller.rb Model: app/models/group_push_rule.rb or ee/app/models/ee/group_push_rule.rb
Additional Context:
- Affects GitLab Dedicated instance (18.7.2)
- Error is consistent and reproducible on the specific affected group
- Correlation ID example:
01KGEH894WW2ZKZE29BBN41KVE
This issue is generated with the help of GitLab Duo.