Problem

  • drupal_rebuild() can run into error conditions itself, triggering Drupal's error/exception handler, but those handlers require a working system/service container + theme system. → Fatal error caused in error handler, hiding the actual error.
  • The error handler itself attempts to iterate over function arguments in a backtrace, without checking whether 'args' is set → PHP notice within error handler, recursively triggering error handler.
  • DrupalKernel::discoverServiceProviders() throws a PHP warning in case an installed module (contained in system.module.yml) no longer exists in the filesystem → Combined with aforementioned error handler issue, the container rebuild fails.
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

damiankloip’s picture

Status: Needs review » Reviewed & tested by the community

Good work! I thought we would run into issues at some point due to the drupal error handling with no container, in their current form. It's better you've found this sooner. These are pretty trivial changes, that make all the difference.

Looks good, and fixes the issue. Replicated on local.

catch’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -230,9 +230,12 @@ public function discoverServiceProviders() {
+      // $module might have been removed from the filesystem.

Unless this results in a fatal (once the rest of the patch is applied) please leave it in. Those errors are useful and shouldn't be hidden. If it's fatal, then trigger_error() or something.

sun’s picture

Status: Needs work » Needs review

Without that condition, the rebuild script shows a PHP notice (native PHP error handler) and depending on display_errors in php.ini, it does not redirect.

I guess that could be considered minor.

However, in case the rebuild happens to fail due to other errors/exceptions later on in dfac(), then I'm back to the same error when going back to the actual site:

Fatal error: Call to a member function get() on a non-object in core\lib\Drupal.php on line 157
{main}( )
drupal_handle_request( )
Drupal\Core\DrupalKernel->boot( )
Drupal\Core\DrupalKernel->initializeContainer( )
Drupal\Core\DrupalKernel->buildContainer( )
Drupal\Core\DrupalKernel->initializeServiceProviders( )
Drupal\Core\DrupalKernel->discoverServiceProviders( )
_drupal_error_handler( )
_drupal_error_handler_real( )
_drupal_log_error( )
watchdog( )
Drupal::request( )

Putting back the isset() adjustment in DrupalKernel, Drupal at least boots on regular pages again.

So I think we should leave it in and commit the patch as-is.

The ultimate goal of the rebuild script is to recover to a functional container/DrupalKernel state. Whenever you have to manually rebuild, something went terribly wrong and there's a 99% chance that the system contains stale data either way.

damiankloip’s picture

So based on that, back to RTBC?

sun’s picture

Status: Needs review » Reviewed & tested by the community

I think so, yes.

webchick’s picture

Assigned: Unassigned » catch

Zoooooom!

sun’s picture

Assigned: catch » Unassigned
FileSize
1.89 KB

After further debugging investigations, I now agree that the change to DrupalKernel should not be contained in here, as the container is continuously rebuilt on every request without any kind of notice or warning that something is wrong.

I'll create a separate issue for that problem.

With that debatable change out of the way, I hope we can move forward here now.

sun’s picture

chx’s picture

Status: Reviewed & tested by the community » Needs work

If the error handler relies on the container that is a bug. _drupal_get_error_level handles one such dependency and if there's more then fix it similarly. I see if (\Drupal::request()->isXmlHttpRequest()) which looks suspicious. I do not know what else is there. But removing the Drupal error handler instead of fixing it is not the solution.

sun’s picture

I'm not able to see the point of trying to get a custom error handler to work in a scenario in which the entire application is known to not be operable?

The custom error handler tries to (1) log using watchdog(), (2) dsm() an error message, (3) initialize the [maintenance] theme, etc.

We can certainly hack the error handler code with further conditionals, but the end result is going to be the same in the concrete case of drupal_rebuild(): The custom error handler is not functional, an error must be displayed and/or logged, so you are able to identify the problem and recover.

Perhaps you can explain what kind of benefit the custom error handler would have (because I fail to see one), and why we want to use it in a scenario in which it and all of the services it attempts to use cannot work?

chx’s picture

My problem is -- are there other situations where this dependency becomes problematic? Early install errors for example?

sun’s picture

All other situations are setting up a special environment and custom container/DrupalKernel, because they already know that services are not available yet. The way that is done is still a big sad mess and should be improved, but that is OT for this issue.

But drupal_rebuild() operates at the opposite end: The only thing it knows is that the application that previously was operable is no longer operable. To which extent, is unknown. It is not able to predict whether the rebuild will succeed or whether it will throw any notices, warnings, errors, or exceptions and break in the middle.

Lastly, drupal_rebuild() does not render an HTML page, but the custom error handler is designed to collect, aggregate, and render errors in a full page output. In turn, we'd only add more spaghetti to the custom error handler and we'd have to add a fragile way to retrieve and render errors in the output of a script that isn't supposed to render a page-alike thing to begin with.

The scope of this issue is limited to the rebuild script. PHP's native error handling does exactly what it is supposed to do and fully matches developer expectations within this limited scope. It is unnecessary to overload it with a custom and fragile behavior.

Anonymous’s picture

Status: Needs work » Reviewed & tested by the community

i think i agree with special-casing drupal_rebuild(), and not relying on a working application in any way to report errors during it's running. i think it makes sense that we don't want to rely on a working drupal at all, and we should just use 'normal' php settings during that time. so, RTBC.

xjm’s picture

7: drupal8.rebuild-errors.7.patch queued for re-testing.

catch’s picture

Status: Reviewed & tested by the community » Fixed

Thanks for #7.

Agreed on the error handler, this is one place I don't mind whatever special-casing is necessary.

Committed/pushed to 8.x, thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.