Magento – How to debug Uncaught TypeError: Argument must be class A, class B given

dependency-injectiondimagento-2.1magento2object-manager

First off, very importantly: This error ONLY happens in production mode. In developer mode it seems to be fine. So those of you who will tell me to clear var/generation: That would break production mode!

Also, this is a 3rd party module that we didn't develop ourselves. I guess I will be contacting the developers of that.

That being said, I want to know how I could debug and solve this myself if I had no other choice. Here is what it looks like in the browser (yes, unlike most Magento exception printing it's all on one line, the browser will linewrap it to avoid horizontal scrolling)

Fatal error: Uncaught TypeError: Argument 1 passed to MGS\Brand\Helper\Data::__construct() must be an instance of Magento\Framework\App\Helper\Context, instance of Magento\Framework\ObjectManager\ObjectManager given, called in /mypath/lib/internal/Magento/Framework/ObjectManager/Factory/AbstractFactory.php on line 93 and defined in /mypath/app/code/MGS/Brand/Helper/Data.php:38 Stack trace: #0 /mypath/lib/internal/Magento/Framework/ObjectManager/Factory/AbstractFactory.php(93): MGS\Brand\Helper\Data->__construct(Object(Magento\Framework\ObjectManager\ObjectManager)) #1 /mypath/lib/internal/Magento/Framework/ObjectManager/Factory/Compiled.php(88): Magento\Framework\ObjectManager\Factory\AbstractFactory->createObject('Mgs\\Brand\\Helpe...', Array) #2 /mypath/lib/internal/Magento/Framework/ObjectManager/ObjectManager.php(71): Magento\Framework\ObjectManager\Factory\Compiled->create('Mgs\\Brand\\Helpe...') #3 /mypath/lib/internal/Magento/Framework/View/TemplateEngine/Php.ph in /mypath/app/code/MGS/Brand/Helper/Data.php on line 38

So let me format that for your viewing pleasure:

Fatal error: Uncaught TypeError: Argument 1 passed to MGS\Brand\Helper\Data::__construct() must be an instance of Magento\Framework\App\Helper\Context, instance of Magento\Framework\ObjectManager\ObjectManager given, 
called in /mypath/lib/internal/Magento/Framework/ObjectManager/Factory/AbstractFactory.php on line 93 and defined in /mypath/app/code/MGS/Brand/Helper/Data.php:38 
Stack trace: 
#0 /mypath/lib/internal/Magento/Framework/ObjectManager/Factory/AbstractFactory.php(93): MGS\Brand\Helper\Data->__construct(Object(Magento\Framework\ObjectManager\ObjectManager)) 
#1 /mypath/lib/internal/Magento/Framework/ObjectManager/Factory/Compiled.php(88): Magento\Framework\ObjectManager\Factory\AbstractFactory->createObject('Mgs\\Brand\\Helpe...', Array) 
#2 /mypath/lib/internal/Magento/Framework/ObjectManager/ObjectManager.php(71): Magento\Framework\ObjectManager\Factory\Compiled->create('Mgs\\Brand\\Helpe...') 
#3 /mypath/lib/internal/Magento/Framework/View/TemplateEngine/Php.ph 
in /mypath/app/code/MGS/Brand/Helper/Data.php on line 38

Notice that the stack trace is cut off at the end of line #3, so I don't know where this could really be called from!

How can I debug this? Is there any way to get the full backtrace?

And how can this only happen in production mode but be totally fine in developer mode?

I'm running Magento 2.1.0 on php-fpm 7.0.12 in an ubuntu-based docker container on an Ubuntu 16.04 server.

Best Answer

Just to clarify as it seems to happen to a lot of people, there's two possible cases.

Let's use the class Bar for all those cases:

class Bar {

    public function __construct(
        \First\Argument $first,
        \Second\Argument $second
    ) {
        // Constructor code
    }
}

NB: please note that in Magento 2, the $data array parameter always comes last: Magento 2: what is the $data array constructor parameter?

Case 1

You have class Foo that extends Bar

class Foo extends Bar {

     public function __construct(
         \First\Argument $first,
         \Second\Argument $second,
         \Test $test,
         \Testtwo $testtwo
     ) {
         parent::__construct($second, $first);
     }
}

The problem : in that case, the call to the parent constructor does not provide the arguments in the right order. To fix that you must match the parent constructor:

parent::__construct($first, $second);

Case 2

You have class Foo that extends Bar

class Foo extends Bar {

     public function __construct(
         \First\Argument $first,
         \Second\Argument $second,
         \Test $test,
         \Testtwo $testtwo
     ) {
         parent::__construct($first, $second);
     }
}

I hear you saying:

What the hell is wrong with this one ?

Well, the answer is : nothing!

Even if that class looks okay you might get the Uncaught TypeError: Argument X passed to Class must be an instance of Class2 error because of the Magento 2 class generation system.

To fix that, simply delete var/generation folder

Extra Case

You have class Foo that extends Bar

class Foo extends Bar {

     public function __construct(
         \Test $test,
         \Testtwo $testtwo,
         \First\Argument $first,
         \Second\Argument $second
     ) {
         parent::__construct($first, $second);
     }
}

In that particular case, the static tests will complain about the order of parameters in the constructor. To fix that you should change:

 public function __construct(
     \First\Argument $first,
     \Second\Argument $second,
     \Test $test,
     \Testtwo $testtwo
 ) {
     parent::__construct($first, $second);
 }
Related Topic