67

I'm getting following error while updating data through CustomerRepositoryInterface

[Magento\Framework\Exception\SessionException]  
Area code not set: Area code must be set before starting a session.

[Magento\Framework\Exception\LocalizedException]  
Area code is not set                              

Following is my di.xml file

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\Console\CommandList">
        <arguments>
            <argument name="commands" xsi:type="array">
                <item name="test1_command" xsi:type="object">Test\Module\Console\Command\Test1Command</item>
                <item name="test2_command" xsi:type="object">Test\Module\Console\Command\Test2Command</item>
            </argument>
        </arguments>
    </type>
</config>
3

13 Answers 13

107

The area is not set in Magento CLI (it is not required for any core commands). It can be set at the beginning of your command's execute method:

/** @var \Magento\Framework\App\State **/
private $state;

public function __construct(\Magento\Framework\App\State $state) {
    $this->state = $state;
    parent::__construct();
}

public function execute() {
    $this->state->setAreaCode(\Magento\Framework\App\Area::AREA_FRONTEND); // or \Magento\Framework\App\Area::AREA_ADMINHTML, depending on your needs
}
12
  • 7
    FYI, you "adminhtml" was not working for me. "admin" worked. Jun 8, 2016 at 8:31
  • 1
    For me it doesn't work (admin or adminhtml) - there is an error: Area code already set. But then, if I comment it out there is exception from subject again. Jul 15, 2016 at 10:11
  • 17
    You should use \Magento\Framework\App\Area::AREA_* constants instead of hardcoded strings
    – 7ochem
    May 11, 2017 at 11:44
  • 7
    It's best not to set the area code in your constructor; whenever you run bin/magento all the constructors are executed, and if the area code is tried to be set 2 times an exception is thrown. It's better to set the area code in your execute()-method, or run your code in store- or area emulation if state is required. Also: constructor dependencies that could trigger a session down the chain should be initialized using a factory or a proxy to prevent dependencies from setting an area code. Mar 2, 2018 at 7:33
  • 2
    Please unset it as a correct answer. It creates exception when we set area code in constructor.
    – Sandipan S
    Mar 26, 2018 at 11:54
47

I've stumbled into this problem again today and it's important to know that this problem is thrown whenever a dependency down the chain initiates an instance that needs to know the state of the application.

In many cases this error is session-bound (since the session needs to know the state of the application (frontend or adminhtml)).

In my case I needed to have Magento\Tax\Api\TaxCalculationInterface in a CLI command, but this requires at some point in it's dependency chain the customer session (probably to get the customer group).

Edit: I found a better solution using proxies. But for histories' sake, here's my previous answer:


To solve this I did not include this interface in my constructor, but rather it's factory:

/**
 * @var \Magento\Tax\Api\TaxCalculationInterfaceFactory
 */
protected $taxCalculationFactory;

/**
 * @param \Magento\Tax\Api\TaxCalculationInterfaceFactory $taxCalculationFactory
 */
public function __construct(
    \Magento\Tax\Api\TaxCalculationInterfaceFactory $taxCalculationFactory
) {
    $this->taxCalculationFactory = $taxCalculationFactory;
}

This way, the class is only instantiated in the one method where I needed it, and no longer in the constructor:

$taxCalculation = $this->taxCalculationFactory->create();

This solved the problem for me in this particular case.


And now the answer using a proxy:

If you don't want to trigger all the dependencies down the chain, you should use a proxy in your constructor. According to the original documentation:

... constructor injection also means that a chain reaction of object instantiation is often the result when you create an object.

and:

... Proxies extend other classes to become lazy-loaded versions of them. That is, a real instance of the class a proxy extends created only after one of the class’s methods is actually called.

So in my situation, with the TaxCalculationInterface, all I had to do was instantiate my tax calculation as a proxy in my constructor:

/**
 * @var \Magento\Tax\Api\TaxCalculationInterface\Proxy
 */
protected $taxCalculation;

/**
 * @param \Magento\Tax\Api\TaxCalculationInterface\Proxy $taxCalculation
 */
public function __construct(
    \Magento\Tax\Api\TaxCalculationInterface\Proxy $taxCalculation
) {
    $this->taxCalculation = $taxCalculation;
}

This way, my class is lazy loaded. That is: it's only instantiated as soon as I call one of it's methods. For example:

$rate = $this->taxCalculation->getCalculatedRate($productRateId);
1
  • this is the correct answer for me. To debug which commands have problems, I comment <item> tags in di.xml for commands definition in my custom modules, and uncommenting every item and compile to test which fails Jun 10, 2022 at 15:50
23

You shouldn't use setAreaCode in the __construct for CLI commands. When you run any command Magento collect and create instance for each script registered in your application. If there are more than one __construct with area code definition you will have the error.

I suppose better to use the execute() method to set area code. Check the catalog module: vendor/magento/module-catalog/Console/Command/ImagesResizeCommand.php

3
  • 1
    Makes sense to me. Anyone else wants to add a comment on this?
    – ermannob
    Jan 3, 2017 at 17:05
  • 1
    This is correct, see also my comment on the accepted answer: It's best not to set the area code in your constructor; whenever you run bin/magento all the constructors are executed, and if the area code is tried to be set 2 times an exception is thrown. It's better to set the area code in your execute()-method, or run your code in store- or area emulation if state is required. Also: constructor dependencies that could trigger a session down the chain should be initialized using a factory or a proxy to prevent dependencies from setting an area code. Mar 2, 2018 at 7:33
  • 1
    but in Magento 2.2, injecting \Magento\Sales\Api\Data\OrderInterface or \Magento\Sales\Api\OrderManagementInterface in command class constructs will call Magento\Framework\Session\SessionManager->__construct() and will end up "area not set". This doesn't happen 2.1. because module-ui/Config/Reader/Definition/Data is introduced in 2.2 how do we solve this? Jan 15, 2019 at 7:51
12

In most cases exception is caused by some actions performed in console command. Solution (instead of setting area code) is to emulate area code and perform action using

$this->state->emulateAreaCode(Area::AREA_ADMINHTML, [$this, 'someAction'], []);

where $state is object of Magento\Framework\App\State. Setting area in different place is a problem, because it can cause conflict between calls.

2
  • I am using this reference and getting the similar error Area code is already set in my controller, can you please help me to get out of this. I have made changes like, calling setareacode in my construct function but getting same error.
    – Gagan
    Feb 21, 2018 at 8:22
7

In magento 2 if you set AreaCode but still get this error then please try following code.

  • Use Magento\Framework\App\Bootstrap;
  • include app/bootstrap.php;
  • $bootstrap = Bootstrap::create(BP, $_SERVER);
  • $objectManager = $bootstrap->getObjectManager();
  • $state = $objectManager->get('Magento\Framework\App\State');
  • $state->setAreaCode('global');
6

for this areaCode issue, if the 'frontend' parameter is not working, try :

$this->_state->setAreaCode(\Magento\Framework\App\Area::AREA_GLOBAL);

was working for me, hope it helps

2
  • In which file should I add this code? I have exactly the same problem. Apr 3, 2018 at 7:43
  • @xxx I had this problem from a custom command, so I wrote this in the command file I created. You can add it in the execute function, with something like : try { $this->_state->... } finally { $this->executeMyCommand() } Apr 3, 2018 at 9:29
6

The problem is that it does not have any method that returns false if the variable area_code has not been set. The way I found it to solve was by creating override of the state class and creating a new method to validate if the area_code was set.

In my file di.xml

    <preference for="Magento\Framework\App\State" type="Webjump\Abacos\App\State" />

Createad file Webjump\Abacos\App\State

namespace Webjump\Abacos\App;

class State extends \Magento\Framework\App\State
{
    public function validateAreaCode()
    {
        if (!isset($this->_areaCode)) {
            return false;
        }
        return true;
    }
}

Use

/**
* @var \Magento\Framework\App\State
*/
protected $state;

public function __construct(
            \Magento\Framework\App\State $state
)
{
$this->state = $state;
if (!$this->state->validateAreaCode()) {
 $this->state->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML);
}
}
1
  • I think it's easier to wrap the setAreaCode() call in a try/catch block Mar 26, 2021 at 14:49
6

Try to upgrade magento using CLI than i found 'area code not define' for session & app.But i can't find which module or theme.so i just do below changes in vendor/magento/framework/App/State.php file & it's working.

public function __construct(
    \Magento\Framework\Config\ScopeInterface $configScope,
    $mode = self::MODE_DEFAULT
) {
    $this->_areaCode = Area::AREA_GLOBAL;
    $this->_configScope = $configScope;
    switch ($mode) {
        ...
    }
}

It's just temporary solution for ignore error you must find out module for that.

2

I have found same issue with Area code while setup upgrade.

Module 'Magento_WebsiteRestriction':Installing data... Area code not set: Area code must be set before starting a session

I have disabled all third party modules and run setup:upgrade

Then I have re-enabled all of third party modules and run same command. Problem is solved for me Hope this is help for you.

3
  • 1
    this is not actually a solution. It's just hiding the dirt under the rug. But good find anyway. It should help during the development process, but it does not make the problem go away.
    – Marius
    Jun 25, 2018 at 8:13
  • Thank you Marius for correcting me. I have find the same case in most of my project and this help me to resolve this.
    – Ravi yadav
    Jun 25, 2018 at 8:15
  • @Marius, would you care to explain why, and let people know the most canonical method to resolve the issue?
    – Bathmat
    Nov 17, 2018 at 18:16
2

I got the solution by using the proxy class. Example is

use Klevu\Search\Model\Product\MagentoProductActionsInterface\Proxy as MagentoProductActionsInterface;

public function __construct(
        MagentoProductActionsInterface $magentoProductActionsInterface
    )
    {
        $this->_magentoProductActionsInterface = $magentoProductActionsInterface;
        parent::__construct();
    }

This fixed my issue

2

Some of my research on this issue indicates that where the console command is declared plays a factor into WHY an area code needs to be defined. If the command is declared in a modules etc/di.xml file, Magento doesn't know what area it is intended for and thus a line like $this->state->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML); is required. However if the command was declared in etc/adminhtml/di.xml the setAreaCode() could be skipped as di.xml specified the area.

One other thing that tripped me up for a while was that I was trying to use \Magento\Sales\Api\Data\OrderInterface in the __construct to be able to load an order. This caused the Area code is not set error. I changed it to \Magento\Sales\Model\OrderRepository and had success. Moral of the story is that some dependencies may have issues with the command scripts for the area for some reason.

1

I was suffering of error 'Area code is not set' running bin/magento setup:upgrade after import database from production. It's a little bit different case than this topic subject, but maybe will help someone. I was able to resolve this issue locally running bin/magento deploy:mode:set developer despite I already was in developer mode. Magento did some configuration adjustments, specially for me debug_logging played role.

0

Setting the area in the command files didn't fix it for me! What did is moving the di.xml where the commands are declared into adminhtml folder(or in frontend if thats what's needed)!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.