jstoller reports on IRC that pointing update.php to a D7 database results in "PHP Fatal error: Call to a member function isScopeActive() on a non-object in /path/to/site/core/includes/bootstrap.inc on line 2610".

Call chain of the bug:

  1. update_prepare_d8_bootstrap()
  2. drupal_install_config_directories()
  3. install_ensure_config_directory
  4. file_prepare_directory
  5. file_stream_wrapper_valid_scheme <= we need to make this not be called.
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

jstoller’s picture

@chx, per your request, I inserted the following at line 2610 in bootstrap.inc:

  if (!drupal_container()) {
    error_log(print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), TRUE), 4);
    exit;
  }

This had no effect. Nothing in the error log.

If I put the backtrace in there without wrapping it in an if statement, then the error log reads:

Array
(
    [0] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/bootstrap.inc
            [line] => 1488
            [function] => language
        )

    [1] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/modules/system/system.module
            [line] => 2021
            [function] => t
        )

    [2] => Array
        (
            [function] => system_stream_wrappers
        )

    [3] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/module.inc
            [line] => 1003
            [function] => call_user_func_array
        )

    [4] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/file.inc
            [line] => 195
            [function] => module_invoke_all
        )

    [5] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/common.inc
            [line] => 4785
            [function] => file_get_stream_wrappers
        )

    [6] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/bootstrap.inc
            [line] => 2119
            [function] => _drupal_bootstrap_code
        )

    [7] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/update.php
            [line] => 462
            [function] => drupal_bootstrap
        )

)
jstoller’s picture

Status: Postponed (maintainer needs more info) » Active

Inserted the following into bootstrap.inc at line 2588:

  if (!is_object(drupal_container())) {
    error_log(print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), TRUE), 4);
    exit;
  }

After running update.php, my Apache log contained the following error:

Array
(
    [0] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/bootstrap.inc
            [line] => 1488
            [function] => language
        )

    [1] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/modules/system/system.module
            [line] => 2021
            [function] => t
        )

    [2] => Array
        (
            [function] => system_stream_wrappers
        )

    [3] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/module.inc
            [line] => 1003
            [function] => call_user_func_array
        )

    [4] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/file.inc
            [line] => 195
            [function] => module_invoke_all
        )

    [5] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/file.inc
            [line] => 251
            [function] => file_get_stream_wrappers
        )

    [6] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/file.inc
            [line] => 288
            [function] => file_stream_wrapper_get_class
        )

    [7] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/file.inc
            [line] => 503
            [function] => file_stream_wrapper_valid_scheme
        )

    [8] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/install.inc
            [line] => 361
            [function] => file_prepare_directory
        )

    [9] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/install.inc
            [line] => 282
            [function] => install_ensure_config_directory
        )

    [10] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/includes/update.inc
            [line] => 135
            [function] => drupal_install_config_directories
        )

    [11] => Array
        (
            [file] => /Users/jeremy/Sites/drupal-8.x/core/update.php
            [line] => 409
            [function] => update_prepare_d8_bootstrap
        )

)
chx’s picture

Status: Active » Needs review
FileSize
591 bytes

Quite often we check the scheme separately before calling file_stream_wrapper_valid_scheme:

346:  if ($scheme && file_stream_wrapper_valid_scheme($scheme)) {
596:  if (empty($uri_scheme) || !file_stream_wrapper_valid_scheme($uri_scheme)) {
1171:  if (!$destination_scheme || !file_stream_wrapper_valid_scheme($destination_scheme)) {
1598:  if ((!$scheme || !file_stream_wrapper_valid_scheme($scheme)) && (substr(PHP_OS, 0, 3) == 'WIN')) {
1671:  if ($scheme && file_stream_wrapper_valid_scheme($scheme)) {
1764:  if ((!$scheme || !file_stream_wrapper_valid_scheme($scheme)) && (substr(PHP_OS, 0, 3) == 'WIN')) {
1800:  if ($scheme && file_stream_wrapper_valid_scheme($scheme)) {

so I have enrolled using this pattern. Alternatively we could make file_stream_wrapper_valid_scheme(FALSE) return FALSE and make the code that much shorter for all of the above.

jstoller’s picture

Status: Needs review » Needs work

I applied the patch. When I load update.php, I get a WSOD and the following in my php error log:
[27-Dec-2012 04:39:39 UTC] PHP Fatal error: Call to a member function isScopeActive() on a non-object in /Users/jeremy/Sites/drupal-8.x/core/includes/bootstrap.inc on line 2622

However, if I reload the page a couple times, then it works.

The first time I load update.php, the /sites/default/files/config_<…>/active/ directory is created, but nothing is in it.

When I reload the browser, /sites/default/files/config_<…>/active/README.txt appears, along with an empty /sites/default/files/config_<…>/staging/ directory.

Reload the browser one more time and everything works as expected. I also see four .yml files show up in /sites/default/files/config_<…>/active/, and /sites/default/files/php/ appears.

I'd guess there's something about that README.txt file that's gumming up the works.

chx’s picture

Status: Needs work » Needs review
FileSize
1.24 KB

Moar!

jstoller’s picture

Status: Needs review » Reviewed & tested by the community

It works! Updates ran as expected.

Alonzo Villanueva’s picture

it worked for me as well

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 1874562_5.patch, failed testing.

chx’s picture

Status: Needs work » Needs review
FileSize
2.64 KB

So, previously getting system_list() primed by the call collecting the wrappers. Now this is removed. The following call chain happens:

  1. WebTestBase::prepareEnvironment
  2. drupal_theme_initialize
  3. list_themes
  4. system_rebuild_theme_data
  5. SystemListingInfo
  6. config('simpletest.settings')

but prepareEnvironment put an empty container in drupal_container so there is no container, no config factory, it just blows up -- and it only blows up in the simpletest test because you need drupal_valid_test_ua() inside prepareEnvironment(). We can safely just ignore that error.

Edit: note that drupal_static_reset and the setting of parent profile happens a bit later.

chx’s picture

Title: upgrade path broken » upgrade path broken due to early file wrappers hook invoke
plach’s picture

@chx:

I think an alternative fix is the index.php hunk of #1862202-17: Objectify the language system, would it make sense to try and get it in here?

plach’s picture

Issue tags: +Needs tests

Btw, looking at the stack trace in #2 the problem seems to lie in t(), which tries to get the language manager from an empty container. I think having the container in place earlier should fix things here.

In any case I think we need tests.

chx’s picture

We need tests against... what? I am glad to write tests but the current upgrade tests pass and I am at a complete loss of why they would do that when all the code patched up here needs to run during an upgrade test anyways and it should totally blow up. I can only chalk it up to differences in environment (like system_list being primed as seen in #9). So, while in theory I agree with the needs tests tag I am at a complete loss of what to write.

That index.php won't solve anything. In general, update must not fire hooks and getting stream wrappers fires hooks. So, that needed to be shut down.

plach’s picture

So, while in theory I agree with the needs tests tag I am at a complete loss of what to write.

We are two, then :)

I agree fixing the stream-wrapper hook invocation is the proper fix, thanks.

chx’s picture

Can we perhaps then go ahead with committing this and writing a test when we figure out what we can? Cos we have two people here confirming that the bug exists and the patch helps.

plach’s picture

Yes, sounds good, although I am afraid also the follow-up would be marked as critical...

Will try to review the patch ASAP.

plach’s picture

I manually tested #19 and it fixes the issue reported in the OP. However I had to perform an additional fix + apply #1871032-4: Taxonomy module fails to install on MyISAM due to too long schema index to complete the upgrade successfully. I still don't get why upgrade path tests don't fail. If we want to skip tests until commit then I'd say this is RTBC.

plach’s picture

Title: upgrade path broken due to early file wrappers hook invoke » Upgrade path broken
FileSize
110 KB
1.32 KB

Forgot the interdiff. I am attaching also the D7 DB I used for testing the upgrade.

chx’s picture

FileSize
1.25 KB
1.71 KB

Except we do not want the SystemListingInfo change and now that the theme init is gone from TestBase, I am curious whether this patch works.

aspilicious’s picture

+++ b/core/modules/user/user.installundefined
@@ -949,7 +949,7 @@ function user_update_8014() {
-        'length' => 255,
+        'length' => 204,
         'not null' => TRUE,

Is this related?

plach’s picture

Yes, the upgrade does not complete without that hunk.

chx’s picture

Note: the only difference from #5 is the hunk mentioned in #20 which, as mentioned in #17 comes from #1871032: Taxonomy module fails to install on MyISAM due to too long schema index. The reason the patch passed now but not before is because we removed a broken drupal_theme_initalize in TestBase::setUp in #1874694: Plugins broke mysteriously.

chx’s picture

Title: Upgrade path broken » Upgrade path broken and yet tests pass
plach’s picture

@chx:

Note: the only difference from #5 is the hunk mentioned in #20 which, as mentioned in #17 comes from #1871032: Taxonomy module fails to install on MyISAM due to too long schema index.

I think I didn't explain myself correctly: the user.install hunk is a missing part of #347988: Move $user->data into own table. To succesfully complete the upgrade we need this patch and #1871032: Taxonomy module fails to install on MyISAM due to too long schema index. We can keep trying to make tests fail here, but we will need that one to be committed before this one otherwise we will have failing tests in HEAD.

plach’s picture

I think I found the reason why tests are not failing: in the first access to update.php config directories and the service container are created for the first time, but in the upgrade tests these are initialized before accessing update.php. This hides the problems we are having here because the config directories are already in place and the stream wrappers do not need to be collected.

The attached interdiff fixes tests to initialize config directories and service container only after the first update.php access. This is supposed to fail to prove the tests capture the bug, while the full patch is supposed to come back green :)

Locally the upgrade path tests are failing due to the user data bug. No idea why the testbots do no fail, are they running tests on MySQL with InnoDB? Anyhow this does not need to be postponed on #1871032: Taxonomy module fails to install on MyISAM due to too long schema index.

plach’s picture

+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
@@ -195,6 +207,16 @@ protected function performUpgrade($register_errors = TRUE) {
+    // Initialize the config directory variables after created in the first step
+    // and rebuild the service container.

This comment needs to be fixed.

Status: Needs review » Needs work

The last submitted patch, drupal-upgrade_path-1874562-25.patch, failed testing.

plach’s picture

This should fix language upgrade tests.

Status: Needs review » Needs work

The last submitted patch, drupal-upgrade_path-1874562-27.patch, failed testing.

plach’s picture

Status: Needs work » Needs review
FileSize
6.81 KB

Wrong patch... this one is what I mean to upload in #27.

chx’s picture

FileSize
824 bytes
6.74 KB

I would rather explicitly check whether the config.factory exists -- most of the time it doesn't.

plach’s picture

Status: Needs review » Reviewed & tested by the community

Definitely better :)

chx’s picture

FileSize
525 bytes
6.31 KB

Meanwhile, a simplification to file_stream_wrapper_valid_scheme went through so one of the hunks is no longer necessary. Doesn't affect functionality.

catch’s picture

#33: 1874562_33.patch queued for re-testing.

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.x, thanks!

Berdir’s picture

    // No operation if the child has not been upgraded yet.
    if (!$this->upgradedSite) {
      global $conf;
      cache('bootstrap')->delete('variables');
      $conf = variable_initialize();
      $container = drupal_container();
      if ($container->has('config.factory')) {
        $container->get('config.factory')->reset();
      }
    }

The condition seems to be backwards here. $this->upgradedSite is initially FALSE and then set to TRUE after the upgrade run through. This seems to reset the variables while the site is not upgraded but not anymore afterwards. Note: The condition has not changed in this patch, it has been like this since this class was added ?!

I noticed this in #1825450: Use lock service in lock() which now tries to use the lock service right after the first call to update.php, but it is not yet defined.

Inverting the check results runs further but then produces the following notice, although it otherwise passes fine:

Undefined index: minimal
system_list('module_enabled')
module_list()
module_load_all_includes('install')
drupal_get_complete_schema(1)
drupal_get_schema(NULL, 1)
drupal_flush_all_caches()
Drupal\simpletest\WebTestBase->resetAll()
Drupal\system\Tests\Upgrade\UpgradePathTestBase->performUpgrade()
Drupal\system\Tests\Upgrade\BareMinimalUpgradePathTest->testBasicMinimalUpgrade()
Drupal\simpletest\TestBase->run()
_simpletest_batch_operation(Array, '6', Array)
call_user_func_array('_simpletest_batch_operation', Array)
_batch_process()
_batch_do()
_batch_page()
system_batch_page()
call_user_func_array('system_batch_page', Array)
Drupal\Core\EventSubscriber\LegacyControllerSubscriber->Drupal\Core\EventSubscriber\{closure}()
call_user_func_array(Object, Array)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1)
Drupal\Core\HttpKernel->handle(Object, 1, 1)
Symfony\Component\HttpKernel\Kernel->handle(Object)
drupal_handle_request()

Which I confirmed also happens in 8.x with that condition is changed.

Berdir’s picture

      $enabled_modules = (array) config('system.module')->get('enabled');
      $module_files = state()->get('system.module.files');
      foreach ($enabled_modules as $name => $weight) {
        // Build a list of all enabled modules.
        $lists['module_enabled'][$name] = $name;
        // Build a list of filenames so drupal_get_filename can use it.
        $lists['filepaths'][] = array(
          'type' => 'module',
          'name' => $name,
          'filepath' => $module_files[$name],
        );
      }

The notice is from 'filepath' => $module_files[$name]. Looks like the config cache got cleared and now contains minimal but state has not been updated?

TechNikh’s picture

I am getting the error when I run drush.

/sites/default# drush status
PHP Fatal error:  Call to a member function isScopeActive() on a non-object in /*********/core/includes/bootstrap.inc on line 2695
PHP Fatal error:  Call to a member function isScopeActive() on a non-object in /*********/core/includes/bootstrap.inc on line 2695

Status: Fixed » Closed (fixed)

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

Anonymous’s picture

Issue summary: View changes

Updated issue summary.