Overview

While uninstalling the module getting below error:
TypeError: str_starts_with(): Argument #1 ($haystack) must be of type string, null given in str_starts_with()

Steps to reproduce

  1. Go to uninstall page /admin/modules/uninstall

Proposed resolution

User interface changes

None.

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

Bhuvaneshwar created an issue. See original summary.

bhuvaneshwar’s picture

Assigned: Unassigned » bhuvaneshwar
wim leers’s picture

Status: Active » Postponed (maintainer needs more info)
Issue tags: +Needs steps to reproduce

Thanks for reporting this! But … it's a mystery to me how to reproduce this, since tests are passing and no backtrace is included.

bhuvaneshwar’s picture

So, when I try to uninstall XB, I encounter this error or by going to the uninstall page.

bhuvaneshwar’s picture

Issue summary: View changes

Here is the stack trace:

TypeError: str_starts_with(): Argument #1 ($haystack) must be of type string, null given in str_starts_with() (line 140 of /var/www/html/modules/experience_builder/src/FieldTypeUninstallValidator.php).

#0 /var/www/html/modules/experience_builder/src/FieldTypeUninstallValidator.php(140): str_starts_with()
#1 /var/www/html/modules/experience_builder/src/FieldTypeUninstallValidator.php(56): Drupal\experience_builder\FieldTypeUninstallValidator->checkDefaultValueUses()
#2 /var/www/html/core/lib/Drupal/Core/Extension/ModuleInstaller.php(645): Drupal\experience_builder\FieldTypeUninstallValidator->validate()
#3 /var/www/html/core/lib/Drupal/Core/ProxyClass/Extension/ModuleInstaller.php(99): Drupal\Core\Extension\ModuleInstaller->validateUninstall()
#4 /var/www/html/core/modules/system/src/Form/ModulesUninstallForm.php(161): Drupal\Core\ProxyClass\Extension\ModuleInstaller->validateUninstall()
#5 [internal function]: Drupal\system\Form\ModulesUninstallForm->buildForm()
#6 /var/www/html/core/lib/Drupal/Core/Form/FormBuilder.php(536): call_user_func_array()
#7 /var/www/html/core/lib/Drupal/Core/Form/FormBuilder.php(284): Drupal\Core\Form\FormBuilder->retrieveForm()
#8 /var/www/html/core/lib/Drupal/Core/Controller/FormController.php(73): Drupal\Core\Form\FormBuilder->buildForm()
#9 [internal function]: Drupal\Core\Controller\FormController->getContentResult()
#10 /var/www/html/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array()
#11 /var/www/html/core/lib/Drupal/Core/Render/Renderer.php(638): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#12 /var/www/html/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(121): Drupal\Core\Render\Renderer->executeInRenderContext()
#13 /var/www/html/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext()
#14 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(181): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#15 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\Component\HttpKernel\HttpKernel->handleRaw()
#16 /var/www/html/core/lib/Drupal/Core/StackMiddleware/Session.php(53): Symfony\Component\HttpKernel\HttpKernel->handle()
#17 /var/www/html/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle()
#18 /var/www/html/core/lib/Drupal/Core/StackMiddleware/ContentLength.php(28): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
#19 /var/www/html/core/modules/big_pipe/src/StackMiddleware/ContentLength.php(32): Drupal\Core\StackMiddleware\ContentLength->handle()
#20 /var/www/html/core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\big_pipe\StackMiddleware\ContentLength->handle()
#21 /var/www/html/core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\page_cache\StackMiddleware\PageCache->pass()
#22 /var/www/html/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\page_cache\StackMiddleware\PageCache->handle()
#23 /var/www/html/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
#24 /var/www/html/core/lib/Drupal/Core/StackMiddleware/AjaxPageState.php(36): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
#25 /var/www/html/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(51): Drupal\Core\StackMiddleware\AjaxPageState->handle()
#26 /var/www/html/core/lib/Drupal/Core/DrupalKernel.php(736): Drupal\Core\StackMiddleware\StackedHttpKernel->handle()
#27 /var/www/html/index.php(19): Drupal\Core\DrupalKernel->handle()
#28 {main}
wim leers’s picture

Status: Postponed (maintainer needs more info) » Active
Issue tags: -Needs steps to reproduce +Needs tests

Aha! Nice catch! 👏

That's something that we should be able to add explicit test coverage for pretty easily I think? 😊

bhuvaneshwar’s picture

Assigned: bhuvaneshwar » Unassigned
Status: Active » Needs work

Test needs to be added

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

utkarsh_33’s picture

Assigned: Unassigned » wim leers
Status: Needs work » Needs review

@wimleers I just added the tests asserting that we are able to load the page which was not happening prior to this fix.Is there something else that needs to be a part of this test?Assigning it to you for the clarifications on this.

wim leers’s picture

Assigned: wim leers » Unassigned
Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs tests

LGTM!

P.S.: I ran the test-only CI job and it passed tests: https://git.drupalcode.org/project/experience_builder/-/jobs/2379770 — which means that there was indeed a test failure, which means that this MR contains the appropriate test coverage. 👍

wim leers’s picture

Status: Reviewed & tested by the community » Needs work

I was wrong:

P.S.: I ran the test-only CI job and it passed tests: https://git.drupalcode.org/project/experience_builder/-/jobs/2379770 — which means that there was indeed a test failure, which means that this MR contains the appropriate test coverage. 👍

That CI job should've failed. The test passes locally without the code changes.

wim leers’s picture

Assigned: Unassigned » wim leers

Found the root cause: the test assertion was inverted … which meant it always passes.

Fixed.

wim leers’s picture

Assigned: wim leers » Unassigned
Status: Needs work » Reviewed & tested by the community
Parent issue: » #3450586: [META] Back-end Kanban issue tracker
Related issues: +#3450957: Prevent modules from being uninstalled if they provide field types used in an Experience Builder field
wim leers’s picture

Assigned: Unassigned » utkarsh_33

If you agree with my changes, then the honor is all yours to merge this MR, @Utkarsh_33! 😄

wim leers’s picture

Assigned: utkarsh_33 » Unassigned
Status: Reviewed & tested by the community » Needs work
Issue tags: +Novice

Too bad, the test fails on PostgreSQL for some reason 🤷‍♀️ See https://git.drupalcode.org/project/experience_builder/-/jobs/2380752

To debug this, add

var_dump($this->getSession()->getPage()->getContent());

temporarily before the failing assertion.

wim leers’s picture

Title: TypeError: str_starts_with(): Argument #1 ($haystack) must be of type string, null given in str_starts_with() » FieldTypeUninstallValidator: TypeError: str_starts_with(): Argument #1 ($haystack) must be of type string, null given in str_starts_with()

omkar-pd made their first commit to this issue’s fork.

omkar-pd’s picture

https://issue.pages.drupalcode.org/-/experience_builder-3464830/-/jobs/2...

The website encountered an unexpected error. Try again later.

Drupal\Core\Database\DatabaseExceptionWrapper: SQLSTATE[42883]: Undefined function: 7 ERROR: function json_extract(jsonb, unknown) does not exist LINE 4: WHERE (JSON_EXTRACT(field_xb_demo_props, '$.*.*.expression')... ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts.: SELECT "node__field_xb_demo"."entity_id" AS "entity_id", "node__field_xb_demo"."revision_id" AS "revision_id" FROM "test69047609node__field_xb_demo" "node__field_xb_demo" WHERE (JSON_EXTRACT(field_xb_demo_props, '$.*.*.expression')::text LIKE '%ℹ︎comment␟%'); Array ( ) in Drupal\experience_builder\FieldTypeUninstallValidator->checkContentEntityUses() (line 212 of /builds/issue/experience_builder-3464830/src/FieldTypeUninstallValidator.php).
wim leers’s picture

Okay, so this error on PostgreSQL:

ERROR: function json_extract(jsonb, unknown) does not exist

is expected.

What is not expected, is that this runs at all, because we have

    if (!isset($connection_info['default']['driver']) || $connection_info['default']['driver'] !== 'mysql') {
      $this->markTestSkipped('This test only runs for the MySQL database driver. See https://drupal.org/i/3452756');
    }

in FieldTypeUninstallValidatorTest.

Conclusion: we expect that UninstallModulePageTest will fail on PostgreSQL too. We have #3452756: Ensure querying JSON nested values when parent keys are unknown is possible in all supported databases for this.

So this needs a slight adjustment to the new UninstallModulePageTest and then it'll be good to go 👍

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

pooja_sharma’s picture

Status: Needs work » Needs review

As per #20 , tweak code of UninstallModulePageTest so that test skip for PostgreSQL only as it fails for this one.

Also observed there are some pipeline failures related : \ComponentValidationTest::randomMachineName() , for this rebased the MR. apart from it nothing seems to be left.

What is not expected, is that this runs at all, because we have

if (!isset($connection_info['default']['driver']) || $connection_info['default']['driver'] !== 'mysql') {
$this->markTestSkipped('This test only runs for the MySQL database driver. See https://drupal.org/i/3452756');
}
in FieldTypeUninstallValidatorTest.

This is kernel test, so here this var $connection_info['default']['driver'] return 'mysql', so this is not run for all which is expected.

Verified if we want var $connection_info['default']['driver'] returns value in string format like 'mysql' then test need to extend from InstallerTestBase.class for functional test otherwise it return Drupal\mysql\Driver\Database\mysql

Please review, moving NR

wim leers’s picture

Status: Needs review » Needs work

Getting close!

pooja_sharma’s picture

Status: Needs work » Needs review

I have tried to address feedback & rebased the MR, Please review, moving to NR

atul_ghate’s picture

StatusFileSize
new3.79 MB
new4.58 MB
new523.87 KB

Hi,

I reviewed MR!143, applied it against Experience Builder 0.x, and confirmed that I can go to the uninstall page without any errors. I was also able to uninstall the module and verified that the module is working correctly.

I’ve added a before-and-after screen recording for reference. RTBC+

Thank you.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

The test-only CI job indeed reproduces the reported bug:

There was 1 error:
1) Drupal\Tests\experience_builder\Functional\UninstallModulePageTest::testUninstallModulePage
Exception: Warning: Undefined array key "expression"
Drupal\experience_builder\FieldTypeUninstallValidator->checkDefaultValueUses()() (Line: 140)

— https://git.drupalcode.org/issue/experience_builder-3464830/-/jobs/2575834

👍

Time to ship this! 🚢 Thanks all 🙏

P.S.: @atul_ghate: please do not post screenshots of a patch successfully applying. That is not remotely helpful. If the MR applies, we already know that it's an applicable patch …

wim leers’s picture

Status: Reviewed & tested by the community » Fixed
kristen pol’s picture

Perhaps a follow-up issue is needed?

kristens-mbp-2:starshot-xb kristenpol$ ddun experience_builder

In PmCommands.php line 200:
                                                                                                                                         
  experience_builder: The <em class="placeholder">Experience Builder</em> field type is used in the following field: node.field_xb_demo  
                                                                                                                                         

Failed to run drush pm:uninstall experience_builder: exit status 1

wim leers’s picture

#29: That's Drupal core's \Drupal\field\FieldUninstallValidator, not XB.

Before uninstall the XB module, you have to first delete all XB field instances. That's true for any module providing a field type.

So no, no follow-up is needed for that 😇

kristen pol’s picture

Ah yes of course… brain is mush.

I have seen some modules that maybe had a friendlier error message or maybe I’m hallucinating at this point 😜

wim leers’s picture

@kristen pol The message is much friendlier also for this scenario … if you use the UI. There's only so much that's possible in a drush CLI context :)

Status: Fixed » Closed (fixed)

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