Logo run_as_root - Magento B2B Agency Würzburg

Adobe Commerce CLI Commands: Creating Problems from Nothing

Technical
Adobe Commerce CLI Commands: Creating Problems from Nothing

Contents

Hello everyone,

In this article, I'll provide practical examples showcasing how unexpected challenges can arise in Magento 2 & Adobe Commerce projects while building and/or using custom CLI commands from 3rd parties. This becomes especially significant while working with CI/CD and performing project setups and test execution in pipelines.

Introducing the main "hero" of our article: ISSUE: magento setup command is throwing magento.flag does't exist. We'll take a deeper look into this issue, understanding its roots and finding ways to address it.

😁

Disclaimer: Just a quick heads-up on naming—both Adobe Commerce and Magento 2 are covered in this article. After all, Adobe Commerce is Magento. Long Live Magento!

The Underlying Problem & Its Roots

While working on various Magento 2 projects, I frequently encountered snags when performing a `clean` setup of a project using a freshly created database. This usually happens during integration or functional test setups in pipelines & local environments. Still, this issue isn't exclusive to that scenario and can pop up during upgrades, migrations, or deployments.

The culprits? Here are two pesky errors you might recognize:

The default website isn't defined. Set the website and try again.

For Commerce editions, there's also:

SQLSTATE[42S02]: Base table or view not found: 1146 Table
'magento2.flag' doesn't exist, query was:
SELECT flag.* FROM flag WHERE (flag.flag_code='staging')

When you see these during the `php bin/magento setup:install` command execution, they offer little insight into the real issue. After a few hair-pulling hours of research, you'd discover these errors stem from the premature invocation of the DB resource, triggering the initialization of config and state entities from the Magento DB.

But here's the conundrum: You can't fetch data from the DB at this point because there aren't any tables present yet. They only appear and populate during the installation process, not beforehand. ¯\_(ツ)_/¯

The Classic "Chicken or the Egg" Dilemma

So, we're caught in a circular problem: trying to install the system but getting stopped because it's not installed. Confusing, right?🤪

This happens because someone, somewhere, is prematurely calling the DB connection resource. It is obvious, and I hope you would be as grateful as Sam Eliot is for this revelation insight.

Thanks Captain Obvious

This "someone" should be inside `bin/magento` and called before actual command execution. Usually, CLI command constructors are guilty here. Let me explain why.

The Pitfall of CLI Command Constructors

For clarity, take a look at this code:

class DoSmthing
{
    private ?string $dummyConfigValue;

    public function __construct(ScopeConfigInterface $storeManager)
    {
        $this->dummyConfigValue = $storeManager->getValue('some/dummy/path', ScopeInterface::SCOPE_STORE);
    }

    public function getValue(): ?string
    {
        return $this->dummyConfigValue;
    }
}

class DummyCommand extends Command
{
    // ...
    public function __construct(DoSmthing $model, string $name = null)
    {
        $this->model = $model;
        parent::__construct($name);
    }
    // ...
}

The root of the problem lies in the constructors of both the command and model classes.

In the DoSmthing class, the system attempts to retrieve a config value. This action calls the store, store_website, and core_config_data tables when creating the DummyCommand object.

And guess what happens when this code runs before the tables are ready? Yep, errors appear!

Let's Repeat One More Time

  1. We execute bin/magento setup:install.
  2. bin/magento application creates all instances of CLI commands.
  3. DummyCommand instance depends on the DoSmthing model, so DoSmthing must be created before DummyCommand object creation.
  4. Application creates DoSmthing model and executes DoSmthing::__construct method.
  5. DoSmthing::__construct method calls the config manager.
  6. Config manager queries a chain of tables that are not yet created.
  7. ERROR.

Strategies to Prevent These Errors

Remember this golden rule: Every CLI command class initializes every time you invoke php bin/magento. So, here's how to save yourself future headaches:

  • Be Wise It is not wise to call resource-consuming operations like DB/API calls in __construct methods of CLI command classes. Those operations will be executed even when simply retrieving a list of available commands.
  • Be Ready Avoid referencing resources in __construct that might not be available during runtime, especially since Magento tables aren't created during setup:install.
  • Fix The Problem If you cannot modify the problematic code, inject a Proxy using DI configurations.

We can solve the issue from our previous example with DummyCommand by adding the following lines to di.xml:

<type name="AbcTest\DummyConsoleCommand\Console\Command\DummyCommand">
    <arguments>
        <argument name="model" xsi:type="object">
            \AbcTest\DummyConsoleCommand\Model\DoSmthing\Proxy
        </argument>
    </arguments>
</type>

Proxy is a well-known pattern, and in Magento, it is widely used to avoid unneeded code execution before we actually request it. In our example — DoSmthing class object will not be instantiated until we call any method of this class.

No config retrieving while CLI class object creation — No error.

More details about proxy here: Proxies.

Simplify with Automated Proxy Injection

For those with a small number of extensions on their project, pinpointing the rogue CLI commands isn't too challenging. However, for more extensive, legacy projects or ones brimming with third-party extensions, identifying the culprits becomes an ordeal.

To save time, we've crafted a solution to automate the proxy injection process. Introducing: run-as-root/magento-cli-auto-proxy.

This package injects Proxy into all __construct arguments of CLI commands, eligible for proxying. The result? No errors related to early resource access and, as a side effect, faster execution of php bin/magento and php bin/magento setup:install.

Check out the README for more details. We always appreciate feedback and contributions!

Summary

Let's sum it up:

  • Unthoughtfully created CLI commands can unexpectedly lead to problems, even if they appear harmless at first.
  • The core of the problem often arises from premature database calls, leading to a classic "chicken or the egg" scenario where system installation gets stalled.
  • One significant pitfall identified is the CLI command constructors and their potential to wreak havoc when invoked at the wrong time.
  • To combat these challenges, we laid out three guiding principles:
  1. Be Wise by avoiding resource-intensive calls in constructors.
  2. Be Ready by steering clear of resources that might not be available.
  3. Fix The Problem by utilizing proxies for problematic third-party code.
  • To streamline and automate the solution, we introduced the package run-as-root/magento-cli-auto-proxy, which aims to automate proxy injections, offering a more efficient and error-free Magento experience.

Thank you for diving deep into this article. I welcome all your questions and appreciate any feedback you might have.

Happy coding and... Long Live Magento! 😁

Optimize Your Adobe Commerce CLI Commands

Connect with Vlad, our Adobe Commerce expert, to enhance your development workflow and resolve CLI command issues.

Book your slot now

Related Articles

Technical
images/blog/why_upgrading_your_software_is_more_than_just_a_chore.webp
Vlad Podorozhnyi Avatar

Vlad Podorozhnyi

25.11.25

Why Upgrading Your Software Is More Than Just a Chore
Technical
/images/blog/blog_INP_corewebvitals_thumbnail.webp
Jordy Scholing Avatar

Jordy Scholing

14.11.25

Debugging INP: from DevTools to RUM Data