Unknown column ‘updated_at’: corrigir o erro no Laravel 13

O Eloquent escreve created_at e updated_at a cada inserção. Se a tabela não tiver estas colunas, o Laravel devolve um erro SQLSTATE 1054. Três correções, consoante a tabela: acrescentar as colunas por migração, desativar os timestamps no modelo ou declarar os nomes reais das colunas com duas constantes.

Unknown column ‘updated_at’: corrigir o erro no Laravel 13
Resposta rápida

O Eloquent escreve created_at e updated_at a cada inserção: o erro significa que a tabela não as tem. Três correções, consoante o caso: acrescenta-as por migração com $table->timestamps(), desativa-as com public $timestamps = false; no modelo, ou declara os seus nomes reais com as constantes CREATED_AT e UPDATED_AT.

A mensagem aparece logo no primeiro save() ou create() sobre um modelo:

code
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'INSERT INTO'

A causa é sempre a mesma: o Eloquent mantém duas colunas de datas, created_at e updated_at, e escreve nelas a cada inserção ou atualização. Se a tabela não as tiver, a consulta falha. Há três formas de resolver isto, e a escolha certa depende da tabela, não das tuas preferências.

Artigo do percurso Desenvolvimento web. Erro reproduzido e correções verificadas no Laravel 13.30.1 com MariaDB 11.8.9.

Reconhecer o erro

O texto varia consoante o motor e a operação, mas aponta sempre para updated_at ou created_at:

code
-- à l'insertion (MySQL / MariaDB)
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'INSERT INTO'

-- à la mise à jour
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'reports.updated_at' in 'SET'

-- sur SQLite
SQLSTATE[HY000]: General error: 1 table reports has no column named updated_at

Começa por verificar o que a tabela contém de facto:

bash
php artisan tinker --execute='echo implode(", ", Schema::getColumnListing("reports"));'
code
id, title

Se created_at e updated_at faltarem, continua a ler. Se existirem com outro nome, salta diretamente para a terceira solução.

Solução 1: acrescentar as colunas

O procedimento completo está descrito no guia das migrações Laravel.

É a resposta certa na maioria dos casos. Saber quando uma linha foi criada e alterada acaba sempre por servir, tanto no debugging como na ordenação. O helper timestamps() cria as duas colunas de uma só vez, nullable:

bash
php artisan make:migration add_timestamps_to_reports_table --table=reports
database/migrations/2026_09_02_000000_add_timestamps_to_reports_table.php
public function up(): void
{
    Schema::table('reports', function (Blueprint $table) {
        $table->timestamps();
    });
}

public function down(): void
{
    Schema::table('reports', function (Blueprint $table) {
        $table->dropTimestamps();
    });
}
bash
php artisan migrate

Depois da migração, a inserção passa e as datas ficam preenchidas. Verificado: a tabela contém mesmo id, title, created_at, updated_at e $report->created_at devolve uma instância de Illuminate\Support\Carbon, que podes formatar e comparar.

Numa tabela que já tem linhas, as colunas são criadas a NULL no existente, o que não levanta problema. Se quiseres um valor, indica-o explicitamente:

php
$table->timestamp('created_at')->nullable()->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrent()->useCurrentOnUpdate();

Solução 2: desativar os timestamps no modelo

Quando a tabela não tem vocação para guardar estas datas, tabela de ligação, referencial fixo ou esquema imposto por um sistema terceiro, , diz-lo ao modelo:

app/Models/Video.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Video extends Model
{
    public $timestamps = false;
}

O Eloquent deixa de preencher as duas colunas e a inserção funciona. Podes confirmar o estado com $video->usesTimestamps(), que devolve false.

A mesma desativação pode ser feita pontualmente numa instância, por exemplo para corrigir um dado sem alterar updated_at:

php
$task->timestamps = false;
$task->title = 'Titre corrigé';
$task->save();   // updated_at fica inalterado
Não desatives para calar o erro

Se a tabela devia ter estas colunas, $timestamps = false não resolve nada: retira uma informação que vais procurar mais tarde. Guarda esta solução para as tabelas onde a data de modificação realmente não faz sentido.

Solução 3: as colunas existem com outro nome

Numa base herdada, as colunas chamam-se muitas vezes date_creation, creation_date ou modified_on. Não vale a pena renomear seja o que for: indica ao Eloquent os nomes reais através de duas constantes.

app/Models/Clip.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Clip extends Model
{
    const CREATED_AT = 'creation_date';
    const UPDATED_AT = 'updated_date';
}

O Eloquent passa a escrever nessas colunas. Verificado no Laravel 13: depois de Clip::create(['title' => 'Extrait']), a coluna creation_date contém mesmo a data e hora, e getUpdatedAtColumn() devolve updated_date.

Se só existir uma das duas datas, põe a outra a null:

php
const CREATED_AT = 'creation_date';
const UPDATED_AT = null;   // nenhuma coluna de atualização

Os acessores $clip->created_at e $clip->updated_at, esses, não seguem estas constantes: devolvem null. Leia a coluna pelo seu nome real, $clip->creation_date, ou de forma genérica com $clip->{$clip->getCreatedAtColumn()}.

Que solução escolher

Situação Solução
Tabela aplicacional normal, colunas simplesmente esquecidas Acrescentar as colunas por migração
Tabela pivô, referencial fixo, esquema imposto public $timestamps = false;
Base herdada com colunas de datas com outro nome Constantes CREATED_AT e UPDATED_AT
Uma única escrita não deve tocar em updated_at $model->timestamps = false; antes do save()

Erros frequentes

Desativar os timestamps para calar o erro Numa tabela aplicacional normal, $timestamps = false apaga uma informação útil em vez de corrigir o esquema. Acrescenta antes as colunas.
Colunas NOT NULL numa tabela já preenchida O timestamps() cria-as nullable, o que passa. Uma definição NOT NULL sem valor por omissão faria falhar a migração.
Renomear as colunas da base herdada Inútil e arriscado: as constantes CREATED_AT e UPDATED_AT bastam para apontar para os nomes existentes.
Esquecer UPDATED_AT = null Se a tabela só tem uma coluna de criação, deixar UPDATED_AT por omissão faz reaparecer o mesmo erro na atualização.

EloquentLaravelMigrationsPHP

Damien Flandrin Programador web desde 2010, criador da Gekkode e do Email Impact. Cada artigo é testado num projeto real antes de ser publicado. Contacto
Newsletter

Os novos testes, tutoriais e projetos, por e-mail.

Testes reproduzíveis, código versionado, resultados datados. Nunca spam.