← Voltar ao blog

Erros comuns do Magento 2 e como corrigir

Rodrigo Biazzi

Alguns erros do Magento voltam em quase todo projeto. Têm mensagens curtas e vagas, e uma busca devolve uma dúzia de threads de fórum, cada uma sugerindo um comando diferente. Rodar comandos aleatórios às vezes faz o erro sumir sem que ninguém entenda por quê, e depois ele volta.

Este artigo passa por seis dos mais comuns no Magento 2.4. Para cada um: o que a mensagem realmente significa, as causas usuais e a correção. Antes de qualquer um deles, dois hábitos gerais ajudam: leia var/log/exception.log e var/log/system.log para ver o stack trace completo e saiba em qual mode a loja roda com bin/magento deploy:mode:show.

"Area code is not set"

O que significa

O Magento carrega a configuração por área: frontend, adminhtml, crontab, webapi_rest, graphql e outras. Requests web definem a área automaticamente. Comandos CLI e scripts avulsos não. Quando um código que precisa de configuração específica de área roda antes de uma área ser definida, você recebe Magento\Framework\Exception\LocalizedException: Area code is not set.

Causas comuns

  • Um console command customizado que salva produtos, envia e-mails ou renderiza templates.
  • Um console command cujo construtor puxa dependências pesadas. Todo comando é instanciado quando o bin/magento inicia, então um construtor que dispara código dependente de área quebra todos os comandos, até os sem relação, como cache:flush.
  • Um script PHP avulso inicializado fora da aplicação normal.

Correção

Defina a área dentro do execute(), nunca no construtor:

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;
}

Aqui appState é um Magento\Framework\App\State injetado, e o catch vazio cobre o caso em que a área já foi definida. Quando só um trecho de código precisa de uma área específica, o emulateAreaCode() da mesma classe roda um callback nessa área e restaura o estado anterior.

Para dependências pesadas no construtor, injete um proxy pelo di.xml para que o objeto real só seja criado quando o comando rodar:

<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"

O que significa

O object manager pediu uma classe que o autoloader não encontra. Muitas vezes o nome da classe termina em Factory, Proxy, Interceptor ou Extension. Essas são classes geradas, escritas na pasta generated sob demanda no developer mode ou pelo setup:di:compile no production mode.

Causas comuns

  • Production mode com código gerado desatualizado ou incompleto, por exemplo depois de um deploy que pulou o setup:di:compile ou depois de habilitar um módulo.
  • Um erro de digitação em um nome de classe no di.xml, em um arquivo de layout ou em um type hint de construtor.
  • O módulo que fornece a classe está desabilitado, ou o namespace dele no composer.json não bate com a pasta.
  • Arquivos em generated pertencentes a outro usuário, então o Magento não consegue escrever a classe nova no developer mode.

Correção

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

No developer mode você pode pular o passo de compile, já que as classes são geradas na próxima request. Se o erro persistir depois de um compile limpo, o problema está no código, não no cache. A saída do compile geralmente nomeia o arquivo com a referência errada. Rode bin/magento module:status Vendor_Module para confirmar que o módulo está habilitado.

"Invalid Form Key. Please refresh the page."

O que significa

Todo POST no Magento carrega um form_key que precisa bater com o guardado na sessão. A mensagem significa que não bateram. Ou o formulário enviou a chave errada, ou não enviou nenhuma, ou a sessão que guarda a chave se perdeu.

Causas comuns

  • Problemas de cookie. Um domain ou path de cookie na configuração que não bate com a URL, mistura de HTTP e HTTPS ou um navegador bloqueando o cookie de sessão. Confira web/cookie/cookie_domain e web/cookie/cookie_path em core_config_data.
  • Sessões removidas. Redis usado para sessões com uma política de maxmemory que remove chaves, ou uma instância compartilhada com o cache que enche. As sessões somem e o POST seguinte falha.
  • Formulários customizados. Um template customizado que monta um formulário sem a chave. Renderize o block formkey dentro do formulário com getBlockHtml('formkey'), ou faça o post por JavaScript enviando o form_key do cookie.
  • Form key em cache. Um block customizado que imprime o form key direto no HTML e é cacheado pelo full page cache, de modo que todo visitante recebe a mesma chave. O core resolve isso atualizando a chave com JavaScript nas páginas em cache. Código customizado não deve contornar isso.
  • Formulários grandes no admin. Uma página de produto ou de configuração com muitos campos pode exceder o max_input_vars do PHP. O PHP descarta os campos extras em silêncio, e se o form key estiver entre eles, o save falha com essa mensagem. Aumente o max_input_vars na configuração do PHP-FPM.

Correção

Descubra qual se aplica antes de mudar qualquer coisa. Abra as ferramentas de desenvolvedor do navegador, olhe o payload do POST em busca de form_key e compare com o cookie form_key. Se forem diferentes, é um problema de cache ou de template. Se baterem mas o erro persistir, o problema é a sessão. Confira o storage de sessão e as configurações de cookie.

Indexers travados

O que significa

O bin/magento indexer:status mostra um indexer como "Processing" por horas, ou "Reindex required" que nunca sai, e a storefront mostra preços antigos, produtos faltando ou estoque errado.

Causas comuns

  • Um processo de reindex foi morto, por timeout, limite de memória ou deploy, e o estado dele nunca foi resetado.
  • Indexers no modo "Update by Schedule" dependem dos cron jobs indexer_update_all_views e indexer_reindex_all_invalid. Se o cron não roda, as tabelas de changelog terminadas em _cl crescem e nada é aplicado.
  • Dois processos de reindex iniciados ao mesmo tempo pelo cron e por alguém na linha de comando.

Correção

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

O indexer:reset marca o indexer como invalid para que um reindex completo possa rodar de novo. Depois confira o cron: a tabela cron_schedule mostra se os jobs de indexer rodaram recentemente e se terminaram com erro. Em lojas de produção, mantenha os indexers em "Update by Schedule" com bin/magento indexer:set-mode schedule e garanta que o cron rode a cada minuto. Reindexes completos em um catálogo grande devem ser planejados, não disparados pelo admin em horário comercial.

"Unable to unserialize value"

O que significa

Isso vem de Magento\Framework\Serialize\Serializer\Json::unserialize(), geralmente com "Error: Syntax error". O Magento esperava uma string JSON e recebeu outra coisa.

Causas comuns

  • Dados antigos no formato serializado do PHP. Antes da 2.2, muitos valores eram guardados com o serialize() do PHP. Uma migração ou um módulo de terceiros que ainda escreve esse formato deixa valores começando com a: onde era esperado JSON.
  • Campos de configuração com um backend model serializado, como linhas dinâmicas na system configuration, editados na mão no banco ou truncados pelo tamanho da coluna.
  • Entradas de cache corrompidas, por exemplo depois de uma remoção no Redis no meio de uma escrita ou de um cache compartilhado entre duas instalações.
  • Uma string vazia ou null passada ao serializer por código customizado.

Correção

Limpe o cache primeiro. Se o erro sumir, era o cache. Se não, ache o valor. O stack trace mostra qual classe chamou o serializer, o que diz se é configuração, uma opção de quote item, um order item ou uma tabela de módulo. Para configuração, procure valores que não são JSON válido:

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

Converta esses valores para JSON com um pequeno script que faça unserialize e encode, ou salve o campo de novo no admin. Corrija o módulo que escreve o formato antigo, senão o erro volta.

Arquivos estáticos retornam 404

O que significa

A página carrega sem estilos, e o console do navegador mostra 404 para arquivos em /static/version.../frontend/....

Causas comuns

  • Production mode sem conteúdo estático publicado, ou publicado para o locale ou tema errado.
  • Falta a regra do web server que remove o segmento de versão das URLs estáticas. A configuração de exemplo do Nginx do Magento e o pub/static/.htaccess incluem essa regra.
  • O document root aponta para a raiz do Magento em vez de pub, então as URLs e as regras de rewrite não casam.
  • Arquivos pertencentes ao usuário errado, ou pub/static esvaziado por um script de deploy.

Correção

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

Faça o deploy de todo locale usado por uma store view e por usuários do admin. No Nginx, compare o seu location block de estáticos com o nginx.conf.sample na raiz do Magento. Ele contém o rewrite de /static/version123/ para /static/ e o fallback para static.php para arquivos ainda não gerados no developer mode.

Uma regra geral

A maioria desses erros é sintoma de algo no ambiente: cron, sessões, passos de deploy, dono dos arquivos. Corrija a causa e escreva isso no script de deploy ou na configuração do servidor, para que a próxima pessoa não procure a mesma mensagem de novo.

FAQ

Como corrijo "Area code is not set" em um console command do Magento 2?

Injete Magento\Framework\App\State e chame setAreaCode dentro do método execute, envolvido em um try e catch. Não defina no construtor e use proxies para dependências pesadas, para que o bin/magento não as carregue na inicialização.

Por que o Magento diz que Class Factory does not exist em production mode?

Factories são classes geradas. Em production mode elas precisam ser criadas pelo bin/magento setup:di:compile. Limpe generated/code e generated/metadata, rode o compile e limpe o cache.

O que causa Invalid Form Key ao salvar um produto no admin?

Muitas vezes um formulário grande que excede o max_input_vars do PHP, que descarta campos, incluindo o form key. Sessões perdidas e configurações erradas de cookie domain são as outras causas usuais.

É seguro rodar indexer:reset?

É. Ele só marca o indexer como invalid para que possa ser reconstruído. Rode indexer:reindex logo depois e evite fazer um reindex completo de um catálogo grande em horário de pico.

Sou Rodrigo Biazzi, desenvolvedor Magento certificado, trabalhando com Magento e Adobe Commerce há mais de 12 anos. Atendo como freelancer em Magento, de correções pontuais a projetos mais longos. Se esse é o tipo de problema que você tem na sua loja, fale comigo.

Artigos relacionados