← Back to blog

Common Magento 2 Errors and How to Fix Them

Rodrigo Biazzi

Some Magento errors come back on almost every project. They have short, vague messages and a search returns a dozen forum threads, each suggesting a different command to run. Running random commands sometimes makes the error go away without anyone understanding why, and then it comes back.

This article goes through six of the most common ones in Magento 2.4. For each one: what the message actually means, the usual causes, and the fix. Before any of them, two general habits help: read var/log/exception.log and var/log/system.log for the full stack trace, and know which mode the store runs in with bin/magento deploy:mode:show.

"Area code is not set"

What it means

Magento loads configuration by area: frontend, adminhtml, crontab, webapi_rest, graphql and others. Web requests set the area automatically. CLI commands and standalone scripts do not. When code that needs area specific configuration runs before an area is set, you get Magento\Framework\Exception\LocalizedException: Area code is not set.

Common causes

  • A custom console command that saves products, sends emails or renders templates.
  • A console command whose constructor pulls in heavy dependencies. Every command is instantiated when bin/magento starts, so a constructor that triggers area dependent code breaks all commands, even unrelated ones like cache:flush.
  • A standalone PHP script bootstrapped outside the normal application.

Fix

Set the area inside execute(), never in the constructor:

protected function execute(InputInterface $input, OutputInterface $output): int
{
    try {
        $this->appState->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML);
    } catch (\Magento\Framework\Exception\LocalizedException $e) {
    }

    $this->exporter->run();

    return \Magento\Framework\Console\Cli::RETURN_SUCCESS;
}

Here appState is an injected Magento\Framework\App\State, and the empty catch covers the case where the area was already set. When only one piece of code needs a specific area, emulateAreaCode() on the same class runs a callback in that area and restores the previous state.

For heavy constructor dependencies, inject a proxy through di.xml so the real object is only created when the command runs:

<type name="Vendor\Module\Console\Command\ExportProducts">
    <arguments>
        <argument name="productRepository" xsi:type="object">Magento\Catalog\Api\ProductRepositoryInterface\Proxy</argument>
    </arguments>
</type>

"Class ... does not exist"

What it means

The object manager was asked for a class the autoloader cannot find. Often the class name ends in Factory, Proxy, Interceptor or Extension. Those are generated classes, written to the generated folder either on demand in developer mode or by setup:di:compile in production mode.

Common causes

  • Production mode with stale or incomplete generated code, for example after a deploy that skipped setup:di:compile or after enabling a module.
  • A typo in a class name in di.xml, a layout file or a constructor type hint.
  • The module that provides the class is disabled, or its namespace in composer.json does not match its folder.
  • Files in generated owned by another user, so Magento cannot write the new class in developer mode.

Fix

rm -rf generated/code/* generated/metadata/*
composer dump-autoload --optimize
bin/magento setup:di:compile
bin/magento cache:flush

In developer mode you can skip the compile step, since classes are generated on the next request. If the error persists after a clean compile, the problem is in the code, not the cache. The compile output usually names the file with the wrong reference. Run bin/magento module:status Vendor_Module to confirm the module is enabled.

"Invalid Form Key. Please refresh the page."

What it means

Every POST in Magento carries a form_key that must match the one stored in the session. The message means they did not match. Either the form sent the wrong key, sent none, or the session that holds the key was lost.

Common causes

  • Cookie problems. A cookie domain or path in the configuration that does not match the URL, mixing HTTP and HTTPS, or a browser blocking the session cookie. Check web/cookie/cookie_domain and web/cookie/cookie_path in core_config_data.
  • Sessions evicted. Redis used for sessions with a maxmemory policy that evicts keys, or a shared instance with the cache that fills up. Sessions disappear and the next POST fails.
  • Custom forms. A custom template that builds a form without the key. Render the formkey block inside the form with getBlockHtml('formkey'), or post through JavaScript that sends the form_key from the cookie.
  • Cached form key. A custom block that prints the form key directly into HTML and is cached by the full page cache, so every visitor gets the same key. Core handles this by updating the key with JavaScript on cached pages. Custom code must not bypass it.
  • Large admin forms. A product or configuration page with many fields can exceed PHP max_input_vars. PHP silently drops the extra fields, and if the form key is among them, the save fails with this message. Raise max_input_vars in the PHP-FPM configuration.

Fix

Find which one applies before changing anything. Open the browser developer tools, look at the POST payload for form_key and compare it with the form_key cookie. If they differ, it is a caching or template problem. If they match but the error persists, the session is the problem. Check the session storage and the cookie settings.

Indexers stuck

What it means

bin/magento indexer:status shows an indexer as "Processing" for hours, or "Reindex required" that never goes away, and the storefront shows old prices, missing products or wrong stock.

Common causes

  • A reindex process was killed, by a timeout, a memory limit or a deploy, and its state was never reset.
  • Indexers in "Update by Schedule" mode depend on cron jobs indexer_update_all_views and indexer_reindex_all_invalid. If cron is not running, the changelog tables ending in _cl grow and nothing is applied.
  • Two reindex processes started at the same time by cron and by someone on the command line.

Fix

bin/magento indexer:status
bin/magento indexer:reset catalog_product_price
bin/magento indexer:reindex catalog_product_price

indexer:reset marks the indexer as invalid so a full reindex is allowed to run again. Then check cron: the cron_schedule table shows whether the indexer jobs ran recently and whether they finished with an error. For production stores, keep indexers on "Update by Schedule" with bin/magento indexer:set-mode schedule and make sure cron runs every minute. Full reindexes on a large catalog should be planned, not triggered from the admin during business hours.

"Unable to unserialize value"

What it means

This comes from Magento\Framework\Serialize\Serializer\Json::unserialize(), usually with "Error: Syntax error". Magento expected a JSON string and got something else.

Common causes

  • Old data in PHP serialized format. Before 2.2, many values were stored with PHP serialize(). A migration or a third party module that still writes that format leaves values starting with a: where JSON is expected.
  • Configuration fields with a serialized backend model, such as dynamic rows in system configuration, edited by hand in the database or truncated by a column length.
  • Corrupt cache entries, for example after a Redis eviction in the middle of a write or a cache shared between two installations.
  • An empty string or null passed to the serializer by custom code.

Fix

Flush the cache first. If the error disappears, it was the cache. If not, find the value. The stack trace shows which class called the serializer, which tells you whether it is configuration, a quote item option, an order item, or a module table. For configuration, look for values that are not valid JSON:

SELECT config_id, path, LEFT(value, 60)
FROM core_config_data
WHERE value LIKE 'a:%' OR value LIKE 's:%';

Convert those values to JSON with a small script that unserializes and encodes them, or save the field again in the admin. Fix the module that writes the old format, otherwise the error returns.

Static files return 404

What it means

The page loads without styles, and the browser console shows 404 for files under /static/version.../frontend/....

Common causes

  • Production mode without deployed static content, or deployed for the wrong locale or theme.
  • The web server rule that strips the version segment from static URLs is missing. Magento's sample Nginx configuration and pub/static/.htaccess include it.
  • The document root points to the Magento root instead of pub, so URLs and rewrite rules do not match.
  • Files owned by the wrong user, or pub/static emptied by a deploy script.

Fix

bin/magento setup:static-content:deploy -f en_US pt_BR
bin/magento cache:flush

Deploy every locale used by a store view and by admin users. For Nginx, compare your static location block with nginx.conf.sample in the Magento root. It contains the rewrite from /static/version123/ to /static/ and the fallback to static.php for files not yet generated in developer mode.

A general rule

Most of these errors are symptoms of something in the environment: cron, sessions, deploy steps, file ownership. Fix the cause and write it into the deploy script or the server configuration, so the next person does not search for the same message again.

FAQ

How do I fix "Area code is not set" in a Magento 2 console command?

Inject Magento\Framework\App\State and call setAreaCode inside the execute method, wrapped in a try and catch. Do not set it in the constructor, and use proxies for heavy dependencies so bin/magento does not load them at start.

Why does Magento say Class Factory does not exist in production mode?

Factories are generated classes. In production mode they must be created by bin/magento setup:di:compile. Clear generated/code and generated/metadata, run the compile, and flush the cache.

What causes Invalid Form Key when saving a product in the admin?

Often a large form exceeding PHP max_input_vars, which drops fields including the form key. Lost sessions and wrong cookie domain settings are the other usual causes.

Is it safe to run indexer:reset?

Yes. It only marks the indexer as invalid so it can be rebuilt. Run indexer:reindex right after it, and avoid doing a full reindex of a large catalog during peak traffic.

I am Rodrigo Biazzi, a Magento Certified Developer working with Magento and Adobe Commerce for more than 12 years. I am available for freelance Magento work, from single fixes to longer projects. If this is the kind of problem you have on your store, get in touch.

Related articles