Behat\Testwork\Call\Exception\FatalThrowableError: Fatal error: Call to a member function get() on null in /home/travis/build/backend/public/modules/contrib/pathauto/pathauto.module:106

Issue fork pathauto-2939432

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

tuutti created an issue. See original summary.

tuutti’s picture

Status: Active » Needs review
berdir’s picture

what entity type is this?

The path field is expected to be computed and auto-loaded, it should always have a field item, even when there is no alias.

tuutti’s picture

We populate a bunch of entities during Behat test that will be automatically deleted after every step. Everything else except nodes and taxonomy terms seems to work just fine.

I've tried to reproduce this without behat, but with no success.

berdir’s picture

which drupal core version? 8.4?

I'll have a closer look at this asap. We should be doing some updates now that path is a able to load itself anyway I think, might also help wit hthis.

tuutti’s picture

8.4

berdir’s picture

Status: Needs review » Postponed (maintainer needs more info)

There were various reports since 8.4 about strange effects. Only found time now to start looking into it. Can you check if #2945734: Fix automated test failures in 8.x-1.x is fixing this for you?

If not, a failing test would be helpful.

tuutti’s picture

Status: Postponed (maintainer needs more info) » Closed (duplicate)
Related issues: +#2945734: Fix automated test failures in 8.x-1.x

#2945734: Fix automated test failures in 8.x-1.x seems to fix this as well. Thanks!

tuutti’s picture

Status: Closed (duplicate) » Active
tuutti’s picture

StatusFileSize
new531 bytes

Also, here's the patch we're using for now.

tuutti’s picture

Status: Active » Needs review
tuutti’s picture

StatusFileSize
new3.19 KB

I dug a bit deeper into this and this seems to break only if you create a new entity and save it before adding a new translation.

For example, this works just fine:

    $node = $this->entityTypeManager->getStorage('node')
      ->create([
        'title' => 'Test',
        'type' => 'article',
        'langcode' => 'en',
        'body' => [
          'value' => 'dsads',
          'format' => 'plain_text',
        ],
      ]);
    $node->addTranslation('fi', [
      'title' => 'Test fi',
      'body' => [
        'value' => 'dsads',
        'format' => 'plain_text',
      ],
    ]);
    $node->save();
    $node->delete();

but this doesn't:

    $node = $this->entityTypeManager->getStorage('node')
      ->create([
        'title' => 'Test',
        'type' => 'article',
        'langcode' => 'en',
        'body' => [
          'value' => 'dsads',
          'format' => 'plain_text',
        ],
      ]);
 
    $node->save();

    $node->addTranslation('fi', [
      'title' => 'Test fi',
      'body' => [
        'value' => 'dsads',
        'format' => 'plain_text',
      ],
    ]);
    $node->save();
    $node->delete();

Status: Needs review » Needs work

The last submitted patch, 12: failing-test-demo.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

tuutti’s picture

StatusFileSize
new3.22 KB
berdir’s picture

Please provide a combined patch as well to show that it passes then.

  1. +++ b/tests/src/Functional/NodeTest.php
    @@ -0,0 +1,123 @@
    +/**
    + * @group pathauto
    + */
    +class NodeTest extends BrowserTestBase {
    +
    +  public static $modules = [
    +    'language',
    

    Needs description for the class and $modules property.

  2. +++ b/tests/src/Functional/NodeTest.php
    @@ -0,0 +1,123 @@
    +  protected function enableTranslation(string $entityType, string $bundle, bool $rebuild = FALSE) {
    +    if (!$this->languageInstalled) {
    +      ConfigurableLanguage::createFromLangcode('fi')
    +        ->save();
    +      $this->languageInstalled = TRUE;
    +    }
    

    why the conditional, this isn't called multiple times?

    $entityType should be $entity_type.

  3. +++ b/tests/src/Functional/NodeTest.php
    @@ -0,0 +1,123 @@
    +
    +    if ($rebuild) {
    +      drupal_static_reset();
    +      \Drupal::entityTypeManager()->clearCachedDefinitions();
    

    this also seems unused?

  4. +++ b/tests/src/Functional/NodeTest.php
    @@ -0,0 +1,123 @@
    +
    +  public function testWorkingNodeDelete() {
    +    $node = $this->createNodeEntity();
    +    $node->addTranslation('fi', [
    +      'title' => 'Test fi',
    +      'body' => [
    +        'value' => 'dsads',
    +        'format' => 'plain_text',
    

    there is nothing in this test that requires it to be a browser test, it should be a kernel test instead.

    One test method is also enough, and once it is fixed, it doesn't make sense to talk about working and non-working as both are working. Instead, name it after what it is testing/doing (testDeleteTranslations() or something like that)

  5. +++ b/tests/src/Functional/NodeTest.php
    @@ -0,0 +1,123 @@
    +  protected function createNodeEntity() {
    +    $node = $this->entityTypeManager->getStorage('node')
    +      ->create([
    +        'title' => 'Test',
    +        'type' => 'article',
    +        'langcode' => 'en',
    +        'body' => [
    +          'value' => 'dsads',
    +          'format' => 'plain_text',
    +        ],
    +      ]);
    +    return $node;
    

    you don't really need a helper function for this, just do it inline and remove the body part, because that field doesn't exist in this test.

tuutti’s picture

Status: Needs work » Needs review
StatusFileSize
new697 bytes
new1.2 KB

I just put something together to test if this was somehow PHP version related, sorry.

Status: Needs review » Needs work

The last submitted patch, 16: 2939432-16.patch, failed testing. View results

tuutti’s picture

Hmm, looks like #2950701: Pathauto pattern is not applied on first node save. might have fixed this as well.

tuutti’s picture

Status: Needs work » Closed (works as designed)
berdir’s picture

Category: Bug report » Task
Status: Closed (works as designed) » Needs work

Good, but more test coverage never hurts, maybe that revert was temporary and then we want to make sure that it doesn't break again, so keeping open as a task to add that, which possibly is the test-only patch that you provided above..

benjy’s picture

Status: Needs work » Needs review
StatusFileSize
new4.85 KB

Re-roll of #16 but moved the logic into the module file as we no longer implement delete in the field item list? Also brought back the functional test from #14.

jhedstrom’s picture

I'm seeing this behavior in pathauto 1.3 when combined with weitzman/drupal-test-traits. The automatic cleanup happens during phpunit's tearDown phase. It only happens occasionally (still don't know exactly what causes it, but it's certain user entities).

jwjoshuawalker’s picture

I'm using Drupal in a headless manner (and all content is created via Entity Interfaces), I have to use this patch #21 to avoid issues.

Though, it hasn't cleanly applied to 1.x-dev for a month+ now, so I've held back at previous pathauto version.

Just chiming in to possibly help discover how/when/why this happens. (Non-UI created content?)

jwjoshuawalker’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

Patch no longer applies to latest dev.

sokru’s picture

StatusFileSize
new4.85 KB

Just a reroll from #21

jwjoshuawalker’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll

Nice! I'll try to test this tomorrow.

zenimagine’s picture

Hi, will the patch be applied to the next version ?

berdir’s picture

Status: Needs review » Needs work
  1. +++ b/tests/src/Functional/NodeTest.php
    @@ -0,0 +1,144 @@
    +
    +/**
    + * @group pathauto
    + */
    +class NodeTest extends BrowserTestBase {
    ...
    +  protected $languageInstalled = FALSE;
    

    This isn't a very descriptive class name, maybe EntityDeleteTest or so?

  2. +++ b/tests/src/Functional/NodeTest.php
    @@ -0,0 +1,144 @@
    +  protected function enableTranslation(string $entityType, string $bundle, bool $rebuild = FALSE) {
    +    if (!$this->languageInstalled) {
    +      ConfigurableLanguage::createFromLangcode('fi')
    +        ->save();
    +      $this->languageInstalled = TRUE;
    +    }
    

    was this method copied from somewhere?

    we only call it once, maybe just inline it into setUp()? then we don't need the dynamic language installed flag and also not the.

    And are we sure that rebuild is actually needed?

    Also looks like this could be a much faster kernel test, we don't do any web requests here?

  3. +++ b/tests/src/Functional/NodeTest.php
    @@ -0,0 +1,144 @@
    +  public function testWorkingNodeDelete() {
    ...
    +  public function testBrokenNodeDelete() {
    

    working and broken aren't really useful method descriptions, because it wouldn't actually be broken anymore?

    Just one method that tests the broken part would I think also be enough.-

sv’s picture

StatusFileSize
new4.97 KB
new746 bytes

Hi, after applying a patch still have an issue, so I've improved it a bit.

raman.b’s picture

Status: Needs work » Needs review
StatusFileSize
new2.7 KB
new5.8 KB

Addressing the pointers from #28 and including the improvement from #29

raman.b’s picture

StatusFileSize
new2.7 KB
new345 bytes

🤔

Status: Needs review » Needs work

The last submitted patch, 31: 2939432-31.patch, failed testing. View results

raman.b’s picture

Status: Needs work » Needs review
StatusFileSize
new2.69 KB
new368 bytes

mably made their first commit to this issue’s fork.

mably’s picture

"Test-only changes" doesn't fail. So not sure all this is really needed.

mably’s picture

Code review of MR #129

The commit adds a null check in PathautoEntityHooks::entityDelete() before calling ->get('pathauto')->purge(). The original code called $entity->get('path')->first()->get('pathauto')->purge() without verifying that first() returns a valid item, which could cause a fatal error: "Call to a member function get() on null".

The fix stores $entity->get('path')->first() in a variable and checks $item instanceof PathautoItem && $item->__isset('pathauto') before proceeding. This is a correct defensive measure.

Test investigation

The test included in the MR (EntityDeleteTest) had several issues:

  • It was missing the path module in $modules, and did not install the node and path_alias entity schemas or pathauto config. As a result, the path field was not available on the node entity and the delete hook's hasField('path') check returned FALSE — the test never actually exercised the fix.
  • It was missing the #[RunTestsInSeparateProcesses] attribute required since Drupal 11.3.
  • The reproduction scenario (create node, add translation, save, delete) does not trigger the bug in current Drupal 11 because ComputedItemListTrait::get() always calls ensureComputedValue(), so first() returns a valid item.

After fixing the test setup, the only way to make first() return NULL is to artificially clear the path field with $node->get('path')->setValue([]) before deletion. This marks the computed value as already resolved while emptying the item list. With this approach, the test correctly crashes without the fix ("Call to a member function get() on null") and passes with it — but it does not correspond to a real-world use case.

Conclusion

The fix itself is correct and harmless as a defensive null check. However, the original bug may no longer be reproducible in Drupal 11 due to changes in ComputedItemListTrait. The test can only verify the fix by artificially creating the null condition.

mably’s picture

Status: Needs review » Closed (cannot reproduce)

Feel free to reopen this issue if you can provide a reproducible scenario on a fresh Drupal instance.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.