Drush and Symfony Errors in Drupal: A Safe, Practical Fix

Illustrated infographic summarizing: Drush Symfony PHP Errors in Drupal: A Safe, Practical Fix

By Greg Nowak. Updated 21 September 2026.

A Drush command that ends in a Symfony or PHP fatal error can look like a deep Drupal failure. Quite often, it is a toolchain problem: the shell starts one Drush installation, that process loads dependencies from somewhere else, and a different PHP runtime completes the mismatch.

That distinction matters when Drush runs database updates, cache rebuilds, cron jobs or deployment hooks. The aim is not merely to make one command pass. It is to restore a predictable environment that developers, CI and production all run the same way.

What an EventDispatcher error actually tells you

An error involving Symfony\Component\EventDispatcher\EventDispatcher::dispatch() points to an incompatible caller and component. Symfony changed the method’s argument order during the Symfony 4.3 transition, with the newer signature becoming the standard in Symfony 5. That history explains why old Drush releases, contributed commands or custom code can fail against newer Symfony packages.

It does not prove that Symfony itself should be downgraded. Start with the file paths in the stack trace. A mixture of global Composer directories and the project’s vendor directory strongly suggests that the wrong Drush executable was selected. If every path is inside the project, investigate its resolved dependencies and custom command code instead.

Diagnose the runtime before changing it

Work from the directory containing composer.json. These checks are non-destructive:

pwd
command -v php
command -v composer
command -v drush
php -v
php --ini
composer --version
composer config --global home
composer show drush/drush
vendor/bin/drush version
vendor/bin/drush status
composer why symfony/event-dispatcher --tree
composer check-platform-reqs

command -v reveals what the shell will execute. Calling vendor/bin/drush bypasses a global Drush installation and tests the copy resolved with the project. Composer’s why command shows which packages introduced EventDispatcher. check-platform-reqs checks the real PHP version and extensions, ignoring any simulated config.platform value.

Result Likely cause Best next move
vendor/bin/drush works, plain drush fails Global binary or shell-path mismatch Change scripts and runbooks to use the project binary
Both Drush commands fail Project dependency, extension or PHP mismatch Inspect Composer’s dependency tree and platform checks
Only production fails Environment or release drift Compare PHP, extensions, lock file and install flags
All failing paths are project-local Unsupported package or custom command Identify the incompatible caller before changing Symfony
A decision matrix for separating executable-path mistakes from genuine project incompatibilities.

If the project Drush works, fix the invocation

Replace unqualified drush calls in deployment scripts, scheduled jobs, CI configuration and operating notes with vendor/bin/drush. A convenient developer alias is fine, but production automation should not depend on whichever executable appears first in a user’s PATH.

Also confirm that cron and deployment users run the intended PHP binary. An interactive shell may use PHP 8.4 while a scheduled task still resolves PHP 8.2, or may load a different php.ini. That is why recording php -v and php --ini in diagnostic output is useful.

If the project Drush fails, let Composer expose the constraint

Do not install an individual Symfony package globally or delete composer.lock as a first response. Those actions replace evidence with a new, unreviewed dependency set.

Use Composer to test the intended Drush major and show its blockers:

composer prohibits drush/drush ^13 --tree
composer prohibits drush/drush ^14 --tree
composer update drush/drush --with-all-dependencies --dry-run

The dry run previews a solution without writing it. A blocker may be Drupal core, the active PHP version, a contributed package or a project constraint. Resolve that specific relationship instead of forcing installation with --ignore-platform-reqs.

If Drush is missing, add it on a branch or in a controlled build environment. Use a normal requirement when production jobs need Drush; use --dev only when production installations deliberately omit development packages and never call it:

composer require drush/drush:^13
# Or, for a compatible Drupal 11.3+ or Drupal 12 project:
composer require drush/drush:^14

vendor/bin/drush status
composer validate
git diff -- composer.json composer.lock

Choose a currently supported combination

The current Drush compatibility table recommends Drush 13 for Drupal 10.2 and later and for Drupal 11. Drush 14 is recommended for Drupal 11.3 and later and for Drupal 12. Both Drush majors require PHP 8.3 or newer. Drush 12 can still be compatible with Drupal 10, but it is no longer the supported line.

Check Drupal’s PHP matrix as well as Drush’s. In September 2026, Drupal 10.4–10.6 support PHP 8.1 through 8.4; Drupal 11.1–11.4 support PHP 8.3 and 8.4, while PHP 8.5 support begins with Drupal 11.3. Drupal 12 requires PHP 8.5. A PHP release being newer does not automatically make it valid for an older Drupal minor.

Deploy the fix as a controlled change

Commit both composer.json and composer.lock, build from the lock file, and test the commands your release actually uses: status, cache rebuild, database updates, configuration import and any project-specific command files. Run composer check-platform-reqs in the target environment before allowing deployment to continue.

For a legacy site that cannot yet move to a supported combination, pin the last compatible project-local Drush release, isolate its runtime and document the limitation. Treat that as containment with an upgrade owner and date—not as a permanent platform decision.

Make the repair last

  • Keep Drush and its exact resolved version under project control.
  • Use the project binary consistently in local, CI, staging and production workflows.
  • Compare CLI PHP versions and loaded configuration across environments.
  • Test Drupal, Drush and PHP compatibility as one upgrade decision.
  • Remove undocumented global dependencies from operational procedures.

The immediate code change may be small. The valuable outcome is a delivery process that produces the same command-line environment every time. If an inherited Drupal platform has accumulated fragile scripts or unclear dependency ownership, Greg can help turn it into a documented, supportable setup.

Related on GrN.dk

Need help with this kind of work?

Talk to Greg about your Drupal delivery setup Get in touch with Greg.

Sources

Latest articles

I learned server operations by breaking my own servers. I want someone who stands next to me while I do it, then does it themselves the week after.

I am good at building and bad at calling. Here is who I want next to me, what is easiest to sell, and how we split it.

An AI assistant can prepare a refund, but a person should approve the exact payment and amount. Here is how to make that approval hold up through execution and retries.

AI can pull together onboarding tasks before a new hire’s first day. See how the manager approves specific access and how outstanding tasks are followed through.

An internal AI assistant can cite an obsolete handbook with confidence. Here is how to manage document ownership, updates, deletions, access and answer review.

Cloudflare Free provides useful website protection, but its rate limiting and bot controls have limits. Here is how to assess them for a WordPress site.

An AI assistant can answer questions and guide customers to a booking. Here are practical boundaries for prices, delivery times, personal data, and contact with a staff member.

Google and Bing now offer first-party AI search visibility reports. Here’s how to build a useful baseline without inventing a misleading GEO score.

AI crawlers can copy a familiar name. Here’s how to verify signed agents at the edge while keeping legitimate automated traffic moving.

A critical Webform release is a reminder to audit every Drupal codebase, configuration and deployment—not just the main production website.