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>
Abdul Samad Abbasi
  • 824
  • 1
  • 6
  • 20
MJ.
  • 839
  • 1
  • 7
  • 10

13 Answers13

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
}
Rafael Corrêa Gomes
  • 13,309
  • 14
  • 84
  • 171
Alex Paliarush
  • 13,751
  • 5
  • 51
  • 55
  • 7
    FYI, you "adminhtml" was not working for me. "admin" worked. – Phoenix128_RiccardoT Jun 08 '16 at 08: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. – Bartosz Kubicki Jul 15 '16 at 10:11
  • 17
    You should use \Magento\Framework\App\Area::AREA_* constants instead of hardcoded strings – 7ochem May 11 '17 at 11:44
  • For me area code admin and adminhtml didn't work however frontend worked. – Shashank Kumrawat Jan 19 '18 at 06:53
  • 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. – Giel Berkers Mar 02 '18 at 07:33
  • 2
    Please unset it as a correct answer. It creates exception when we set area code in constructor. – Sandipan S Mar 26 '18 at 11:54
  • In which file should we add this code? I have exactly the same error. – Magento Learner Apr 03 '18 at 07:42
  • The answer has been updated and added to execute() method instead of __construct()

    But on CLI command it is good to set Global area code instead of Frontend $this->appState->setAreaCode(\Magento\Framework\App\Area::AREA_GLOBAL);

    – Sandipan S Jun 01 '18 at 05:37
  • I would say that correct answer is emulating area code and running function causing exception in emulated area code. – Bartosz Kubicki Aug 13 '18 at 11:24
  • 1
    Please follow this article to know the details which might help you http://tagvibe.com/magento2/how-to-fix-the-area-code-not-set-issue/ – rajat kara Sep 06 '20 at 19:06
  • where can I put this code? – huykon225 Feb 23 '21 at 04:54
  • 1
    Thanks @rajatkara , your link helped me.I placed the di.xml file inside the adminhtml and used the area code as adminhtml and it worked. – Bharath Kumar Oct 16 '22 at 14:34
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);
Giel Berkers
  • 12,237
  • 7
  • 76
  • 122
  • this is the correct answer for me. To debug which commands have problems, I comment tags in di.xml for commands definition in my custom modules, and uncommenting every item and compile to test which fails – cnbandicoot Jun 10 '22 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

7ochem
  • 7,532
  • 14
  • 51
  • 80
Eugene Kovalyov
  • 231
  • 2
  • 2
  • 1
    Makes sense to me. Anyone else wants to add a comment on this? – ermannob Jan 03 '17 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. – Giel Berkers Mar 02 '18 at 07: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?

    – Yohanes Pradono Jan 15 '19 at 07: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.

Bartosz Kubicki
  • 2,943
  • 3
  • 29
  • 50
  • 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 '18 at 08:22
  • https://magento.stackexchange.com/questions/175549/how-to-programmatically-sign-in-to-the-administration-area-from-a-module – Gagan Feb 21 '18 at 08:28
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');
Black
  • 3,310
  • 4
  • 31
  • 110
rakesh prajapati
  • 630
  • 5
  • 11
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

DependencyHell
  • 1,278
  • 12
  • 25
  • In which file should I add this code? I have exactly the same problem. – Magento Learner Apr 03 '18 at 07: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() } – DependencyHell Apr 03 '18 at 09: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);
}
}
Luan Alves
  • 69
  • 1
  • 2
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.

himansu
  • 224
  • 2
  • 8
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.

Ravi yadav
  • 31
  • 1
  • 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 '18 at 08: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 '18 at 08:15
  • @Marius, would you care to explain why, and let people know the most canonical method to resolve the issue? – Bathmat Nov 17 '18 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

Tejas Vyas
  • 800
  • 8
  • 21
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.

PromInc
  • 460
  • 3
  • 7
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)!

Annak942
  • 59
  • 5