Loading
fix: #3631526 Plain error messages for moderation, keys, rate limits and timeouts
Issue: #3631526 "Initialize the AI Media module"
Chunk 2 of the UX and integration plan (20 October 2026): moderation and error wording (plan sections 2.3 and 6.2).
Depends on !8 (closed) (3631526-guardrail-stops), which depends on !6 (merged). Until those merge, this diff includes them; the change of this MR is its last commit.
What changed
- Moderation:
AiUnsafePromptExceptionmay come from the site's own moderation (AI External Moderation) as well as the provider, so the message no longer blames the provider: "This description was flagged as unsafe and was not sent. Change it and try again." Administrators get a link to the AI moderation settings, and the exception text (which names the moderation provider) under "Details". - Keys: the AI module wraps HTTP client errors as
AiBadRequestException, so a refused key read as "could not use this description". The HTTP status in the exception chain is now read: 401 and 403 give "Generation is not available right now" (administrators: "Check the API key."), 429 gives the rate limit message. - Timeout: a timed-out request reads "The AI service took too long. Try again, or ask for something simpler." Administrators see the AI module's
request_timeoutvalue and a link to the AI settings where it is changed. - Wording per plan 6.2: "The AI service could not use this description", "Too many requests right now. Wait a minute and try again." The administrator detail is labelled "Details", not "Provider message".
- AI Media adds no moderation of its own. The troubleshooting page now lists every message, its cause and what administrators see.
- Unchanged: the description is kept, focus returns to it, and the error is announced assertively once; the format check still runs before any call.
How it was tested
- Kernel
ErrorMessagesTest(9 cases, editor and administrator each): moderation flag, 401, 403, quota, rate limit exception, 429, timeout (cURL error 28), 400 and an unknown error. A test subscriber throws each error the way the AI module wraps it. All 15 Kernel tests of the module pass. - phpcs (Drupal, DrupalPractice), phpstan level 1, cspell, eslint, stylelint: clean.
Not tested
- A real moderation endpoint flagging a prompt, a real revoked key and a real timeout (simulated in the Kernel test, no paid calls).
- No new e2e scenario: Echo cannot be made to fail like a provider in the browser suite; the existing suite runs in CI.
AI-Generated: Yes. Written with Claude Code (Claude Opus 5.5) under the Drupal AI policy; tested by the author before submission.
Checkpoints:
- File an issue
- Addition/Change/Update/Fix
- Testing to ensure no regression
- Automated unit testing coverage
- Automated functional testing coverage
- UX/UI designer responsibilities
- Readability
- Accessibility
- Performance
- Security
- Developer Documentation
- User Guide Documentation
- Reviewed by human
- Code review by maintainers
- Full testing and approval
- Credit contributors
- Review with the product owner
- Release notes snippet
- Release