Fix the error shown when Duo group settings fail to save
What does this MR do and why?
When a save fails on the group GitLab Duo settings page, the alert reads
"An error occurred while retrieving your settings. Reload the page to try
again." Nothing is retrieved on that path, because the only request is the
PUT that just failed. The server's field-level message is handed to
captureError and then dropped, so an owner cannot tell which setting was
rejected.
This rewords the message for a save and appends the server's field-level
messages when the response carries a validation hash, so the alert names the
setting. Fields are named by their existing translated label, and a field
with no label is omitted, following formatServerValidations in
targeted_message_form.vue. Sentry still receives the full error.
locale/gitlab.pot is regenerated in the same commit.
References
#606282 quotes the string. The 400 that produced it was fixed in 19.3 by !244394 (merged) and !247516 (merged), which stopped the form sending an unchanged locked field and guarded the cascading setters server-side. The message itself was not touched, and a save can still fail: a stale form racing another edit, or a validation this page does not model.
How to reproduce
Captured on a self-managed 19.2.4 instance, before the two fixes above.
-
As instance admin, open Admin > GitLab Duo > Configuration (
/admin/gitlab_duo/configuration), clear Allow external agents, and save. This setslock_duo_external_agents_enabledon the instance. -
As owner of any group, open Settings > General > GitLab Duo, change one unrelated and unlocked control such as Allow custom flows, and save.
-
PUT /api/v4/groups/:idreturns400. The form submits every Duo availability key, including the locked one it renders as disabled, so the response body is:{"message":{"namespace_settings.lock_duo_external_agents_enabled":["cannot be changed because it is locked by an ancestor"]}} -
The alert reads "An error occurred while retrieving your settings. Reload the page to try again.", and nothing is saved.
On master the same sequence returns 200, so to see the string there, block
the PUT in devtools and save.
Screenshots or screen recordings
| Before | After |
|---|---|
![]() |
![]() |
The after image was captured on a source checkout of this branch with the PUT stubbed to return the 19.2.4 validation body; on master the lock case itself returns 200 because the form sends only changed keys.
How to set up and validate locally
-
Run the specs for the touched files:
yarn jest ee/spec/frontend/ai/settings/utils_spec.js \ ee/spec/frontend/ai/settings/pages/ai_group_settings_spec.js -
On a running instance, block the
PUTin devtools and save. The alert shows the reworded message with nothing appended. -
Make the save return a validation hash for a locked field, either by the reproduction above on 19.2.x or by stubbing the 400. The alert names the setting.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
AI-Generated Content Disclosure: This MR was prepared with assistance from Claude Code. The output has been reviewed for correctness, the reproduction was verified on a running 19.2.4 instance, and the change was validated with the specs and lint named above.

