When AI‑Generated Code Meets Legacy Drupal: A Horror Story
(Client and environment details anonymized.)
The Setup: A Simple Form That Wasn’t
What started as a “quick bugfix” spiraled into a multi‑day debugging run: conflicting email systems, infinite redirects, and the realization that parts of the codebase had been stitched together by AI assistants with zero awareness of the project’s architecture.
Symptom: users submitted a form but saw no success message and received no confirmation email. Root cause: several small, generic snippets interacting in all the wrong ways.
The First Red Flag: <front>
Buried in a form handler, I found this:
<?php
return new RedirectResponse(Url::fromRoute('<front>')->toString());
Looks harmless. In reality, <front> is generic boilerplate AI tools love to suggest.
Here, it clashed with Drupal’s own form redirect flow, preventing user success messages from ever appearing.
The Cascade of Failures
1) Three Email Systems, One Message
- Drupal YAML email handler
- Custom PHP utility (legacy)
- Global hook on submission
All three tried to send the same confirmation. None agreed on recipients. Some referenced placeholder values; others bypassed handler enablement.
2) The _default Value Trap
settings:
to_mail: _default
subject: _default
from_mail: _default
Intended to resolve into real addresses, left literal instead.
Result: attempts like “from info@example.com to _default”. Delivery: none.
3) Redirect Loops Instead of Business Logic
Form A always redirected to Form B. Form B always redirected to Form A. The actual rule was conditional: certain users should stop after Form A and receive a notification. The hardcoded loop ignored that completely.
4) User Feedback Coupled to Backend Validation
<?php
if ($nb_demande > 0) {
\Drupal::messenger()->addMessage(t('Success!'), 'status');
}
If a backend rightly rejected the request, the user saw nothing - not even a “we got your submission” info. Confidence killer.
The AI Smoking Gun
- Generic redirects where project‑specific routes were required
- Token usage without session integration (e.g., swapping custom tokens without wiring)
- Email helpers overwriting their own recipient arrays
- Errors logged server‑side, zero UX feedback client‑side
Each snippet looked fine in isolation - together, they collapsed.
The Fix: Less Code, Not More
- Remove duplication: disable redundant PHP mail calls; use the single YAML handler.
- Use supported tokens: replace broken custom tokens with standard ones like
[current-user:mail](or project‑specific, wired properly). - Override redirects conditionally: enforce business rules in PHP when config is too generic.
- Decouple UX from backend verdicts: always acknowledge submission; show separate messages for validation outcomes.
Lessons Learned
For Developers
- AI‑generated code defaults to generic patterns - verify architectural fit.
- Multiple systems solving the same problem is a smell.
- Never couple user feedback to backend acceptance; acknowledge first, validate second.
For Teams Using AI
- Code reviews should sniff out boilerplate patterns, not just syntax errors.
- Integration tests matter most in legacy contexts.
- Document AI‑assisted code paths; gate architectural changes through senior review.
The Real Cost
This “small fix” took days across multiple components. The bigger hit was to user trust, plus the hidden interest on technical debt from piling AI snippets on top of legacy flows.
Conclusion
AI tools are excellent at neat, isolated snippets. But in complex Drupal stacks, context is the battlefield. Before copy‑pasting that perfect answer into production, remember: it doesn’t know your tokens, sessions, or business rules.
Sometimes the best code is the code you don’t write.
Have you hit a similar AI‑code trap? I’m happy to review and untangle tricky integrations - reach out via LinkedIn or email.