Erros comuns do Magento 2 e como corrigir
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/magentoinicia, então um construtor que dispara código dependente de área quebra todos os comandos, até os sem relação, comocache: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:compileou 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.jsonnão bate com a pasta. - Arquivos em
generatedpertencentes 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_domaineweb/cookie/cookie_pathemcore_config_data. - Sessões removidas. Redis usado para sessões com uma política de
maxmemoryque 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
formkeydentro do formulário comgetBlockHtml('formkey'), ou faça o post por JavaScript enviando oform_keydo 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_varsdo 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 omax_input_varsna 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_viewseindexer_reindex_all_invalid. Se o cron não roda, as tabelas de changelog terminadas em_clcrescem 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 coma: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
nullpassada 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/.htaccessincluem 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/staticesvaziado 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
GraphQL no Magento 2: adicione uma query e um resolver customizados
Como adicionar uma query GraphQL customizada no Magento 2.4: schema.graphqls, resolver com ResolverInterface, erros, checagem de auth e cache identity para o Varnish.
Shipping method customizado no Magento 2: crie um módulo de carrier
Como criar um shipping method customizado no Magento 2.4: config.xml, system.xml, um carrier model com collectRates, regras de frete grátis e APIs externas de tarifa.
Checklist de limpeza de malware no Magento 2 para lojistas
Checklist defensivo para uma loja Magento 2 hackeada: sinais de comprometimento, achar código injetado em arquivos e banco, rebuild limpo, novas credenciais e hardening.
Backup e restore no Magento 2: o que salvar e como
Como fazer backup e restore de uma loja Magento 2: dumps de banco que importam sem erro, mídia, env.php e a chave de criptografia, cópias offsite e restores testados.