"Warning: session_id(): Cannot change session id" when cron runs to delete abandoned carts

Created on 11 May 2020, about 5 years ago
Updated 14 September 2023, over 1 year ago

I have my site configured to delete abandoned carts after 7 days. This warning is logged when cron runs to delete those carts:

Warning: session_id(): Cannot change session id when headers already sent in Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy->setId() (line 94 of /var/www/mysite/vendor/symfony/http-foundation/Session/Storage/Proxy/AbstractProxy.php)

#0 /var/www/mysite/web/core/includes/bootstrap.inc(600): _drupal_error_handler_real(2, 'session_id(): C...', '/var/www/mysite/ve...', 94, Array)
#1 [internal function]: _drupal_error_handler(2, 'session_id(): C...', '/var/www/mysite/ve...', 94, Array)
#2 /var/www/mysite/vendor/symfony/http-foundation/Session/Storage/Proxy/AbstractProxy.php(94): session_id('U7QhxOu8ZtNqx19...')
#3 /var/www/mysite/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php(183): Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy->setId('U7QhxOu8ZtNqx19...')
#4 /var/www/mysite/web/core/lib/Drupal/Core/Session/SessionManager.php(131): Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->setId('U7QhxOu8ZtNqx19...')
#5 /var/www/mysite/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php(321): Drupal\Core\Session\SessionManager->start()
#6 /var/www/mysite/vendor/symfony/http-foundation/Session/Session.php(256): Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->getBag('attributes')
#7 /var/www/mysite/vendor/symfony/http-foundation/Session/Session.php(280): Symfony\Component\HttpFoundation\Session\Session->getBag('attributes')
#8 /var/www/mysite/vendor/symfony/http-foundation/Session/Session.php(73): Symfony\Component\HttpFoundation\Session\Session->getAttributeBag()
#9 /var/www/mysite/web/modules/contrib/commerce/modules/cart/src/CartSession.php(61): Symfony\Component\HttpFoundation\Session\Session->get('commerce_cart_o...', Array)
#10 /var/www/mysite/web/modules/contrib/commerce/modules/cart/commerce_cart.module(115): Drupal\commerce_cart\CartSession->deleteCartId('5294')
#11 [internal function]: commerce_cart_commerce_order_delete(Object(Drupal\commerce_order\Entity\Order))
#12 /var/www/mysite/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(403): call_user_func_array('commerce_cart_c...', Array)
#13 /var/www/mysite/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(204): Drupal\Core\Extension\ModuleHandler->invokeAll('commerce_order_...', Array)
#14 /var/www/mysite/web/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php(843): Drupal\Core\Entity\EntityStorageBase->invokeHook('delete', Object(Drupal\commerce_order\Entity\Order))
#15 /var/www/mysite/web/modules/contrib/commerce/src/CommerceContentEntityStorage.php(100): Drupal\Core\Entity\ContentEntityStorageBase->invokeHook('delete', Object(Drupal\commerce_order\Entity\Order))
#16 /var/www/mysite/web/modules/contrib/commerce/modules/order/src/OrderStorage.php(111): Drupal\commerce\CommerceContentEntityStorage->invokeHook('delete', Object(Drupal\commerce_order\Entity\Order))
#17 /var/www/mysite/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(434): Drupal\commerce_order\OrderStorage->invokeHook('delete', Object(Drupal\commerce_order\Entity\Order))
#18 /var/www/mysite/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php(786): Drupal\Core\Entity\EntityStorageBase->delete(Array)
#19 /var/www/mysite/web/modules/contrib/commerce/modules/cart/src/Plugin/QueueWorker/CartExpiration.php(98): Drupal\Core\Entity\Sql\SqlContentEntityStorage->delete(Array)
#20 /var/www/mysite/web/core/lib/Drupal/Core/Cron.php(180): Drupal\commerce_cart\Plugin\QueueWorker\CartExpiration->processItem(Array)
#21 /var/www/mysite/web/core/lib/Drupal/Core/Cron.php(145): Drupal\Core\Cron->processQueues()
#22 /var/www/mysite/web/core/lib/Drupal/Core/ProxyClass/Cron.php(75): Drupal\Core\Cron->run()
#23 /var/www/mysite/web/core/modules/automated_cron/src/EventSubscriber/AutomatedCron.php(65): Drupal\Core\ProxyClass\Cron->run()
#24 [internal function]: Drupal\automated_cron\EventSubscriber\AutomatedCron->onTerminate(Object(Symfony\Component\HttpKernel\Event\PostResponseEvent), 'kernel.terminat...', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher))
#25 /var/www/mysite/web/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func(Array, Object(Symfony\Component\HttpKernel\Event\PostResponseEvent), 'kernel.terminat...', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher))
#26 /var/www/mysite/vendor/symfony/http-kernel/HttpKernel.php(88): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.terminat...', Object(Symfony\Component\HttpKernel\Event\PostResponseEvent))
#27 /var/www/mysite/vendor/stack/builder/src/Stack/StackedHttpKernel.php(32): Symfony\Component\HttpKernel\HttpKernel->terminate(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Render\HtmlResponse))
#28 /var/www/mysite/web/core/lib/Drupal/Core/DrupalKernel.php(686): Stack\StackedHttpKernel->terminate(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Render\HtmlResponse))
#29 /var/www/mysite/web/index.php(22): Drupal\Core\DrupalKernel->terminate(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Render\HtmlResponse))
#30 {main}
πŸ› Bug report
Status

Needs review

Version

2.0

Component

Cart

Created by

πŸ‡ΊπŸ‡ΈUnited States sah62 US

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡¨πŸ‡¦Canada joelpittet Vancouver

    The only patch that seemed to have any luck with is #5 #3135550-5: "Warning: session_id(): Cannot change session id" when cron runs to delete abandoned carts β†’ , I tried #14 and #12 and it still failed.

    We are using our own custom IPN
    https://github.com/ubc-cpsc/commerce_touchnet_upay/

    I'm going to take #5 and add one method back at time to see where it's helping.

    For the record this is what our watchdog log is showing:

    RuntimeException: Failed to start the session because headers have already been sent by "" at line 0. in Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->start() (line 132 of vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php).

    The line 0 sent by "" is super frustrating to debug... but it's reproducible (somewhat) in staging so hopefully we get to the bottom of it.

  • πŸ‡¨πŸ‡¦Canada joelpittet Vancouver

    Ok I just added logging lines to that and after the onNotify is complete it runs:

    1. deleteCartId
    2. addCartId

    Here's are callstack and both calls are coming from OrderEventSubscriber::finalizeCart Which for me is anonymous user

      public function finalizeCart(OrderInterface $cart, $save_cart = TRUE) {
    ...
        // The cart is anonymous, move it to the 'completed' session.
        if (!$cart->getCustomerId()) {
          $this->cartSession->deleteCartId($cart->id(), CartSession::ACTIVE);
          $this->cartSession->addCartId($cart->id(), CartSession::COMPLETED);
    ...
      }
    [
        {
            "file": "modules/contrib/commerce/modules/cart/src/CartProvider.php",
            "line": 123,
            "function": "addCartId",
            "class": "Drupal\commerce_cart\CartSession",
            "object": @,
            "type": "->",
            "args": [
                "47",
                "completed"
            ]
        },
        {
            "file": "modules/contrib/commerce/modules/cart/src/EventSubscriber/OrderEventSubscriber.php",
            "line": 47,
            "function": "finalizeCart",
            "class": "Drupal\commerce_cart\CartProvider",
            "object": @,
            "type": "->",
            "args": [
                @,
                false
            ]
        },
        {
            "function": "finalizeCart",
            "class": "Drupal\commerce_cart\EventSubscriber\OrderEventSubscriber",
            "object": @,
            "type": "->",
            "args": [
                @,
                "commerce_order.place.pre_transition",
                @
            ]
        },
        {
            "file": "core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php",
            "line": 111,
            "function": "call_user_func",
            "args": [
                [
                    @,
                    "finalizeCart"
                ],
                @,
                "commerce_order.place.pre_transition",
                @
            ]
        },
        {
            "file": "modules/contrib/state_machine/src/Plugin/Field/FieldType/StateItem.php",
            "line": 422,
            "function": "dispatch",
            "class": "Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher",
            "object": @,
            "type": "->",
            "args": [
                @,
                "commerce_order.place.pre_transition"
            ]
        },
        {
            "file": "modules/contrib/state_machine/src/Plugin/Field/FieldType/StateItem.php",
            "line": 380,
            "function": "dispatchTransitionEvent",
            "class": "Drupal\state_machine\Plugin\Field\FieldType\StateItem",
            "object": @,
            "type": "->",
            "args": [
                "pre_transition"
            ]
        },
        {
            "file": "core/lib/Drupal/Core/Field/FieldItemList.php",
            "line": 233,
            "function": "preSave",
            "class": "Drupal\state_machine\Plugin\Field\FieldType\StateItem",
            "object": @,
            "type": "->",
            "args": []
        },
        {
            "file": "core/lib/Drupal/Core/Field/FieldItemList.php",
            "line": 191,
            "function": "delegateMethod",
            "class": "Drupal\Core\Field\FieldItemList",
            "object": @,
            "type": "->",
            "args": [
                "preSave"
            ]
        },
        {
            "file": "core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php",
            "line": 938,
            "function": "preSave",
            "class": "Drupal\Core\Field\FieldItemList",
            "object": @,
            "type": "->",
            "args": []
        },
        {
            "file": "core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php",
            "line": 888,
            "function": "invokeFieldMethod",
            "class": "Drupal\Core\Entity\ContentEntityStorageBase",
            "object": @,
            "type": "->",
            "args": [
                "preSave",
                @
            ]
        },
        {
            "file": "modules/contrib/commerce/src/CommerceContentEntityStorage.php",
            "line": 56,
            "function": "invokeHook",
            "class": "Drupal\Core\Entity\ContentEntityStorageBase",
            "object": @,
            "type": "->",
            "args": [
                "presave",
                @
            ]
        },
        {
            "file": "modules/contrib/commerce/modules/order/src/OrderStorage.php",
            "line": 81,
            "function": "invokeHook",
            "class": "Drupal\commerce\CommerceContentEntityStorage",
            "object": @,
            "type": "->",
            "args": [
                "presave",
                @
            ]
        },
        {
            "file": "core/lib/Drupal/Core/Entity/EntityStorageBase.php",
            "line": 529,
            "function": "invokeHook",
            "class": "Drupal\commerce_order\OrderStorage",
            "object": @,
            "type": "->",
            "args": [
                "presave",
                @
            ]
        },
        {
            "file": "core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php",
            "line": 753,
            "function": "doPreSave",
            "class": "Drupal\Core\Entity\EntityStorageBase",
            "object": @,
            "type": "->",
            "args": [
                @
            ]
        },
        {
            "file": "core/lib/Drupal/Core/Entity/EntityStorageBase.php",
            "line": 483,
            "function": "doPreSave",
            "class": "Drupal\Core\Entity\ContentEntityStorageBase",
            "object": @,
            "type": "->",
            "args": [
                @
            ]
        },
        {
            "file": "core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php",
            "line": 806,
            "function": "save",
            "class": "Drupal\Core\Entity\EntityStorageBase",
            "object": @,
            "type": "->",
            "args": [
                @
            ]
        },
        {
            "file": "modules/contrib/commerce/modules/order/src/OrderStorage.php",
            "line": 159,
            "function": "save",
            "class": "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
            "object": @,
            "type": "->",
            "args": [
                @
            ]
        },
        {
            "file": "core/lib/Drupal/Core/Entity/EntityBase.php",
            "line": 339,
            "function": "save",
            "class": "Drupal\commerce_order\OrderStorage",
            "object": @,
            "type": "->",
            "args": [
                @
            ]
        },
        {
            "file": "modules/contrib/commerce/modules/payment/src/PaymentOrderUpdater.php",
            "line": 101,
            "function": "save",
            "class": "Drupal\Core\Entity\EntityBase",
            "object": @,
            "type": "->",
            "args": []
        },
        {
            "file": "modules/contrib/commerce/modules/payment/src/PaymentOrderUpdater.php",
            "line": 59,
            "function": "updateOrder",
            "class": "Drupal\commerce_payment\PaymentOrderUpdater",
            "object": @,
            "type": "->",
            "args": [
                @,
                true
            ]
        },
        {
            "file": "modules/contrib/commerce/modules/payment/src/PaymentOrderUpdater.php",
            "line": 112,
            "function": "updateOrders",
            "class": "Drupal\commerce_payment\PaymentOrderUpdater",
            "object": @,
            "type": "->",
            "args": []
        },
        {
            "file": "core/lib/Drupal/Core/EventSubscriber/KernelDestructionSubscriber.php",
            "line": 51,
            "function": "destruct",
            "class": "Drupal\commerce_payment\PaymentOrderUpdater",
            "object": @,
            "type": "->",
            "args": []
        },
        {
            "function": "onKernelTerminate",
            "class": "Drupal\Core\EventSubscriber\KernelDestructionSubscriber",
            "object": @,
            "type": "->",
            "args": [
                @,
                "kernel.terminate",
                @
            ]
        },
        {
            "file": "core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php",
            "line": 111,
            "function": "call_user_func",
            "args": [
                [
                    @,
                    "onKernelTerminate"
                ],
                @,
                "kernel.terminate",
                @
            ]
        },
        {
            "file": "vendor/symfony/http-kernel/HttpKernel.php",
            "line": 100,
            "function": "dispatch",
            "class": "Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher",
            "object": @,
            "type": "->",
            "args": [
                @,
                "kernel.terminate"
            ]
        },
        {
            "file": "core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php",
            "line": 63,
            "function": "terminate",
            "class": "Symfony\Component\HttpKernel\HttpKernel",
            "object": @,
            "type": "->",
            "args": [
                {
                    "attributes": @,
                    "request": @,
                    "query": @,
                    "server": @,
                    "files": @,
                    "cookies": @,
                    "headers": @
                },
                {
                    "headers": @
                }
            ]
        },
        {
            "file": "core/lib/Drupal/Core/DrupalKernel.php",
            "line": 688,
            "function": "terminate",
            "class": "Drupal\Core\StackMiddleware\StackedHttpKernel",
            "object": @,
            "type": "->",
            "args": [
                {
                    "attributes": @,
                    "request": @,
                    "query": @,
                    "server": @,
                    "files": @,
                    "cookies": @,
                    "headers": @
                },
                {
                    "headers": @
                }
            ]
        },
        {
            "file": "index.php",
            "line": 22,
            "function": "terminate",
            "class": "Drupal\Core\DrupalKernel",
            "object": @,
            "type": "->",
            "args": [
                {
                    "attributes": @,
                    "request": @,
                    "query": @,
                    "server": @,
                    "files": @,
                    "cookies": @,
                    "headers": @
                },
                {
                    "headers": @
                }
            ]
        }
    ]
  • πŸ‡¨πŸ‡¦Canada joelpittet Vancouver

    Realizing now this looks like @casey's patch in #14 should solve it for us.

  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 8.0 & MySQL 5.7
    last update over 1 year ago
    735 pass, 18 fail
  • πŸ‡¨πŸ‡¦Canada joelpittet Vancouver

    Here's a very specific solution but hopefully that helps with the cases where this finalization step may be needed. I checked if the cart/order's payment gateway has implemented OffsitePaymentGatewayInterface and then compared the current request URL against the one from the gateway's getNotifyUrl method, if it matches then don't mess with the session.

    Hopefully I didn't make any implicit dependencies on the payment in cart that weren't already there.

    I was going to check if a session already started like others before were considering but what if the session needs to be started to do that for the legit user...

  • πŸ‡¨πŸ‡¦Canada joelpittet Vancouver

    I just realized I hijacked this issue for IPN as I re-read the title :( If the maintainers prefer let me know and I'll move my patch to a new issue.

Production build 0.71.5 2024