Diagnosing errors preventing Drush commands from completing properly

When using Drush to interact with your Drupal site via command-line, you may encounter problems in the site's code or configuration that prevent Drush commands from completing properly. These errors present a message like this one:

Drush command terminated abnormally due to an unrecoverable error.                                                 [error]

The source of these error messages can be difficult to diagnose in some cases. In this article, we'll discuss some techniques you can use to pinpoint the underlying problems preventing your Drush commands from running properly.

Run your Drush command in verbose debugging mode

In many cases, the only action you'll need to take in order to reveal the source of the errors causing your Drush commands to terminate abnormally is to run your commands with verbose debugging output enabled. You can accomplish this simply by running your desired command with the "--verbose" and "--debug" options, or simply "-vd", like so:

drush --verbose --debug status

or

drush -vd status

Including these options will tell Drush to print all of its startup and execution output to your terminal window, including any status, warning or error messages leading up to the "Drush command terminated abnormally" error messages mentioned above. In many cases, you'll see some informative PHP warning or error text directly preceding this message, which Drush would normally suppress. This text may also include a filename and line number to indicate the location of the underlying problem in your site's codebase.

Ensure that Drupal is not trying to redirect Drush commands as if they were HTTP requests

Sometimes, Drush commands terminate abnormally because part of your site's code is treating them like HTTP requests, and forcing PHP to exit prematurely in an attempt to redirect the request to a location on the web (an HTTP 301 or 302 response), or prevent it from accessing your site's content due to a lack of HTTP Basic Authentication credentials (an HTTP 401 response). This problematic behavior will typically not produce any PHP warning or error text and, therefore, can be especially difficult to diagnose when troubleshooting problems with Drush commands. Fortunately, many of the problems caused by this behavior occur on specific parts of your site's codebase, which can be temporarily modified in order to debug these issues. We'll discuss two of the most common locations below:

Commands are being redirected via drupal_goto

For sites running Drupal 7 or earlier, the process of redirecting an HTTP request to a new location (a 301: Moved Permanently or 302: Moved Temporarily response) involves a function called drupal_goto, which delivers the response headers required to perform the redirect, and exits Drupal and PHP, and will cause Drush commands to exit abnormally if invoked while Drupal is running in command-line mode. This function is provided by Drupal Core as a utility for use by contributed and custom modules. In order to address problems caused by the invocation of drupal_goto during Drush commands, you'll need to locate the function that invokes drupal_goto. To do this, you can temporarily modify the drupal_goto function definition in Drupal Core's includes/common.inc file:

if (PHP_SAPI === 'cli') {
  print 'Error! Redirected to ' . $path . ', but running in command-line mode!' . PHP_EOL;
  debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}

This code, when encountered in command-line mode, will print the URL that your site is attempting to redirect to via drupal_goto, and a PHP backtrace of the function calls leading up to the invocation of drupal_goto. This backtrace can be used to identify the location in your codebase where this redirect is being initiated, and can help you to narrow in on the code or configuration problem responsible for these Drush errors.

Commands are being denied access during HTTP Basic Authentication

Many Drupal users choose to prevent unauthorized access to their site using HTTP Basic Authentication. This mechanism will deny access to any incoming HTTP request (via an HTTP 401: Unauthorized response) unless they provide the appropriate credentials (an encoded username and password) via the "Authorization" request header. When this security measure is implemented using PHP, as with the contributed Shield module, it has the potential to impact Drush commands as well as HTTP requests unless special precautions are taken. When Drush commands are prevented from completing in this fashion, you may see a message like "Access Denied" in addition to the "command terminated abnormally" message mentioned above. In some cases, the restriction of Drush functionality via Basic Authentication is intentional. In many cases, however, it is the result of a code or configuration problem.

For the Shield module, specifically, the restriction of Drush commands via Basic Authentication depends on the value of a configuration variable that can be changed on the module's administration page:

  • For Drupal 8 sites, this is the "allow_cli" property of the "shield.settings" configuration object, and is used in the Drupal\Shield\ShieldMiddleware::handle method defined in src/ShieldMiddleware.php.
  • For Drupal 7 sites, this is the "shield_allow_cli" variable, and is used in the shield_set_status function defined in shield.module.

In either case, if this setting is misconfigured so that Drush commands are being restricted inadvertently, you won't be able to correct the problem via command-line (drush config-set or variable-set) without modifying the Shield module's code to temporarily disable Basic Authentication. The most straightforward solution to this problem can be achieved by navigating to Shield's configuration page via the web, and adjusting the appropriate configuration value from there.

Both scenarios described above highlight an important design consideration when writing Drupal code which has the potential to exit Drupal before page output can be delivered. Unless your intention with such code is to execute HTTP and command-line requests, you'll want to consider wrapping your code in this conditional statement, that will prevent it from being executed in command-line mode:

if (PHP_SAPI !== 'cli') {

  // HTTP Basic Auth, Redirection, etc.

}

This precaution serves to prevent your code from impeding Drush commands from completing properly in the future.

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.

Contact supportStill need assistance? Contact Acquia Support