A happy-ending story about tackling a Magento bug with ease.
Recently, I've received feedback about the Live Preview feature: live reload doesn't work on some Magento installations and the following exception is logged:
Magento\Framework\Webapi\Exception: Server cannot match any of the given Accept HTTP header media type(s) from the request: "text/event-stream" with media types from the config of response renderer.
The trace lead to RendererFactory::_getRendererClass method:
foreach ($this->getAcceptTypes() as $acceptType) {
foreach ($this->_renders as $rendererConfig) {
$rendererType = $rendererConfig['type'];
if ($acceptType == $rendererType || ...) {
return $rendererConfig['model'];
}
}
}
throw new \Magento\Framework\Webapi\Exception(...);
My first thought was: "Okay, you don't know what is event-stream is, so I'll send multiple 'Accept' headers including text/event-stream". At this point, I wasn't paying attention to anything else in the stack trace — I was eager to fix the annoying exception.
I was hoping to pass additional headers, just like in regular fetch request.
Something like:
headers: {
'Accept': 'text/event-stream,application/json'
}
My plan was flawed from the start — I just didn’t know it yet. 😅
So, I opened js file that creates EventSource, opened MDN
article in anticipation of adding proper headers for Magento...
What the hell!? No headers option? Damn!
Okay, no easy fix for now. I've looked at the stack trace again, and this time I noticed the namepaces for Exception and RendererFactory — Webapi, and Rest\Response? How come? I'm not using REST 🤔. QuoteValidator?? Something strange is going on.
#0 vendor/magento/framework/Webapi/Rest/Response/RendererFactory.php(54): Magento\Framework\Webapi\Rest\Response\RendererFactory->_getRendererClass()
#1 vendor/magento/framework/Webapi/Rest/Response.php(45): Magento\Framework\Webapi\Rest\Response\RendererFactory->get()
#2 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(121): Magento\Framework\Webapi\Rest\Response->__construct(Object(Magento\Framework\Webapi\Rest\Response\RendererFactory), Object(Magento\Framework\Webapi\ErrorProcessor), Object(Magento\Framework\App\State\Interceptor))
#3 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(66): Magento\Framework\ObjectManager\Factory\AbstractFactory->createObject('Magento\Framewo...', Array)
#4 vendor/magento/framework/ObjectManager/ObjectManager.php(73): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->create('Magento\Framewo...')
#5 vendor/magento/module-quote/Model/QuoteValidator.php(72): Magento\Framework\ObjectManager\ObjectManager->get('Magento\Framewo...')
#6 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(121): Magento\Quote\Model\QuoteValidator->__construct(NULL, NULL, NULL, NULL)
#7 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(66): Magento\Framework\ObjectManager\Factory\AbstractFactory->createObject('Magento\Quote\M...', Array)
#8 vendor/magento/framework/ObjectManager/ObjectManager.php(73): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->create('Magento\Quote\M...')
#9 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(170): Magento\Framework\ObjectManager\ObjectManager->get('Magento\Quote\M...')
#10 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(276): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgument(Array, 'Magento\Quote\M...', NULL, 'quoteValidator', 'Magento\Quote\M...')
#11 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(239): Magento\Framework\ObjectManager\Factory\AbstractFactory->getResolvedArgument('Magento\Quote\M...', Array, Array)
#12 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(34): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgumentsInRuntime('Magento\Quote\M...', Array, Array)
#13 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(59): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->_resolveArguments('Magento\Quote\M...', Array, Array)
#14 vendor/magento/framework/ObjectManager/ObjectManager.php(73): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->create('Magento\Quote\M...')
#15 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(170): Magento\Framework\ObjectManager\ObjectManager->get('Magento\Quote\M...')
#16 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(276): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgument(Array, 'Magento\Quote\M...', NULL, 'submitQuoteVali...', 'Magento\Quote\M...')
#17 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(239): Magento\Framework\ObjectManager\Factory\AbstractFactory->getResolvedArgument('Magento\Quote\M...', Array, Array)
#18 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(34): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgumentsInRuntime('Magento\Quote\M...', Array, Array)
#19 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(59): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->_resolveArguments('Magento\Quote\M...', Array, Array)
#20 vendor/magento/framework/ObjectManager/ObjectManager.php(73): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->create('Magento\Quote\M...')
#21 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(170): Magento\Framework\ObjectManager\ObjectManager->get('Magento\Quote\M...')
#22 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(276): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgument(Array, 'Magento\Quote\A...', NULL, 'quoteManagement', 'Magento\Sales\M...')
#23 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(239): Magento\Framework\ObjectManager\Factory\AbstractFactory->getResolvedArgument('Magento\Sales\M...', Array, Array)
#24 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(34): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgumentsInRuntime('Magento\Sales\M...', Array, Array)
#25 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(59): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->_resolveArguments('Magento\Sales\M...', Array, Array)
#26 vendor/magento/framework/ObjectManager/ObjectManager.php(73): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->create('Magento\Sales\M...')
#27 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(170): Magento\Framework\ObjectManager\ObjectManager->get('Magento\Sales\M...')
#28 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(276): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgument(Array, 'Magento\Sales\M...', NULL, 'orderCreate', 'Magento\Sales\B...')
#29 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(239): Magento\Framework\ObjectManager\Factory\AbstractFactory->getResolvedArgument('Magento\Sales\B...', Array, Array)
#30 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(34): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgumentsInRuntime('Magento\Sales\B...', Array, Array)
#31 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(59): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->_resolveArguments('Magento\Sales\B...', Array, Array)
#32 vendor/magento/framework/ObjectManager/ObjectManager.php(73): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->create('Magento\Sales\B...')
#33 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(170): Magento\Framework\ObjectManager\ObjectManager->get('Magento\Sales\B...')
#34 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(276): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgument(Array, 'Magento\Sales\B...', NULL, 'adminOrderAddre...', 'StripeIntegrati...')
#35 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(239): Magento\Framework\ObjectManager\Factory\AbstractFactory->getResolvedArgument('StripeIntegrati...', Array, Array)
#36 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(34): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgumentsInRuntime('StripeIntegrati...', Array, Array)
#37 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(59): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->_resolveArguments('StripeIntegrati...', Array, Array)
#38 vendor/magento/framework/ObjectManager/ObjectManager.php(73): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->create('StripeIntegrati...')
#39 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(170): Magento\Framework\ObjectManager\ObjectManager->get('StripeIntegrati...')
#40 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(276): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgument(Array, 'StripeIntegrati...', NULL, 'helper', 'StripeIntegrati...')
#41 vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(239): Magento\Framework\ObjectManager\Factory\AbstractFactory->getResolvedArgument('StripeIntegrati...', Array, Array)
#42 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(34): Magento\Framework\ObjectManager\Factory\AbstractFactory->resolveArgumentsInRuntime('StripeIntegrati...', Array, Array)
#43 vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(59): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->_resolveArguments('StripeIntegrati...', Array, Array)
#44 vendor/magento/framework/ObjectManager/ObjectManager.php(73): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->create('StripeIntegrati...')
#45 vendor/magento/framework/Interception/PluginList/PluginList.php(173): Magento\Framework\ObjectManager\ObjectManager->get('StripeIntegrati...')
#46 vendor/magento/framework/Interception/Interceptor.php(119): Magento\Framework\Interception\PluginList\PluginList->getPlugin('Melios\PageBuil...', 'stripe_context_...')
#47 vendor/magento/framework/Interception/Interceptor.php(153): Melios\PageBuilderPro\Controller\Preview\Events\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Framework\App\Request\Http))
#48 generated/code/Melios/PageBuilderPro/Controller/Preview/Events/Interceptor.php(32): Melios\PageBuilderPro\Controller\Preview\Events\Interceptor->___callPlugins('dispatch', Array, Array)
#49 vendor/magento/framework/App/FrontController.php(245): Melios\PageBuilderPro\Controller\Preview\Events\Interceptor->dispatch(Object(Magento\Framework\App\Request\Http))
#50 vendor/magento/framework/App/FrontController.php(212): Magento\Framework\App\FrontController->getActionResponse(Object(Melios\PageBuilderPro\Controller\Preview\Events\Interceptor), Object(Magento\Framework\App\Request\Http))
#51 vendor/magento/framework/App/FrontController.php(146): Magento\Framework\App\FrontController->processRequest(Object(Magento\Framework\App\Request\Http), Object(Melios\PageBuilderPro\Controller\Preview\Events\Interceptor))
#52 vendor/magento/framework/Interception/Interceptor.php(58): Magento\Framework\App\FrontController->dispatch(Object(Magento\Framework\App\Request\Http))
#53 vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\App\FrontController\Interceptor->___callParent('dispatch', Array)
#54 vendor/magento/module-store/App/FrontController/Plugin/RequestPreprocessor.php(99): Magento\Framework\App\FrontController\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Framework\App\Request\Http))
#55 vendor/magento/framework/Interception/Interceptor.php(135): Magento\Store\App\FrontController\Plugin\RequestPreprocessor->aroundDispatch(Object(Magento\Framework\App\FrontController\Interceptor), Object(Closure), Object(Magento\Framework\App\Request\Http))
#56 vendor/magento/module-page-cache/Model/App/FrontController/BuiltinPlugin.php(76): Magento\Framework\App\FrontController\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Framework\App\Request\Http))
#57 vendor/magento/framework/Interception/Interceptor.php(135): Magento\PageCache\Model\App\FrontController\BuiltinPlugin->aroundDispatch(Object(Magento\Framework\App\FrontController\Interceptor), Object(Closure), Object(Magento\Framework\App\Request\Http))
#58 vendor/magento/framework/Interception/Interceptor.php(153): Magento\Framework\App\FrontController\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Framework\App\Request\Http))
#59 vendor/magento/framework/App/FrontController.php(23): Magento\Framework\App\FrontController\Interceptor->___callPlugins('dispatch', Array, NULL)
#60 vendor/magento/framework/App/Http.php(116): Magento\Framework\App\FrontController\Interceptor->dispatch(Object(Magento\Framework\App\Request\Http))
#61 vendor/magento/framework/Interception/Interceptor.php(58): Magento\Framework\App\Http->launch()
#62 vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\App\Http\Interceptor->___callParent('launch', Array)
#63 vendor/magento/module-application-performance-monitor/Plugin/ApplicationPerformanceMonitor.php(38): Magento\Framework\App\Http\Interceptor->Magento\Framework\Interception\{closure}()
#64 vendor/magento/framework/Interception/Interceptor.php(135): Magento\ApplicationPerformanceMonitor\Plugin\ApplicationPerformanceMonitor->aroundLaunch(Object(Magento\Framework\App\Http\Interceptor), Object(Closure))
#65 vendor/magento/framework/Interception/Interceptor.php(153): Magento\Framework\App\Http\Interceptor->Magento\Framework\Interception\{closure}()
#66 vendor/magento/framework/App/Http.php(23): Magento\Framework\App\Http\Interceptor->___callPlugins('launch', Array, NULL)
#67 vendor/magento/framework/App/Bootstrap.php(264): Magento\Framework\App\Http\Interceptor->launch()
#68 pub/index.php(30): Magento\Framework\App\Bootstrap->run(Object(Magento\Framework\App\Http\Interceptor))
#69 ~/.composer/vendor/laravel/valet/server.php(110): require('...')
It's time to use the force of GitHub issues: #38907
/checkout page.<type name="Magento\Framework\App\Action\AbstractAction">
<plugin name="stripe_context_currency" type="StripeIntegration\Payments\Plugin\Context" sortOrder="100"/>
</type>
Let's check the stack trace once again. If the plugin was created for my controller, there must be an Interceptor.php in the trace.
And there it is — line 48:
#48 generated/code/Melios/PageBuilderPro/Controller/Preview/Events/Interceptor.php(32): Melios\PageBuilderPro\Controller\Preview\Events\Interceptor->___callPlugins('dispatch', Array, Array)
That's a bummer! How do I fix this unfortunate issue?
Hey! I remember that Decomposition of Magento Controllers PR by Lukasz Bajsarowicz that allowed removing parent class from the frontend controllers!
It was merged back in 2020 and now it's a recommended way to write frontend controllers.
-class Events extends \Magento\Framework\App\Action\Action
+class Events implements \Magento\Framework\App\ActionInterface
That's it! Easiest fix ever!
Keep your code up to date! Don't write such a global plugins like Stripe did!