
Eloquent scrive created_at e updated_at a ogni inserimento: l'errore dice che la tabella non le possiede. Tre correttivi, secondo il caso: aggiungile con una migration usando $table->timestamps(), disattivale con public $timestamps = false; sul modello, oppure dichiara i loro nomi reali con le costanti CREATED_AT e UPDATED_AT.
Il messaggio arriva al primo save() o create() su un modello:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'INSERT INTO'La causa è sempre la stessa: Eloquent tiene aggiornate due colonne di date, created_at e updated_at, e le scrive a ogni inserimento o aggiornamento. Se la tabella non le ha, la query fallisce. Ci sono tre modi per rimettere le cose a posto, e la scelta giusta dipende dalla tabella, non dai tuoi gusti.
Articolo del percorso Sviluppo web. Errore riprodotto e correzioni verificate su Laravel 13.30.1 con MariaDB 11.8.9.
Riconoscere l’errore
Il testo cambia a seconda del motore e dell’operazione, ma punta sempre su updated_at o created_at:
-- à 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_atComincia col guardare che cosa contiene davvero la tabella:
php artisan tinker --execute='echo implode(", ", Schema::getColumnListing("reports"));'id, titleSe created_at e updated_at mancano, vai avanti. Se ci sono ma con un altro nome, salta direttamente alla terza soluzione.
Soluzione 1: aggiungere le colonne
La procedura completa è descritta nella guida alle migration di Laravel.
Nella maggior parte dei casi è questa la risposta giusta. Sapere quando una riga è stata creata e modificata serve prima o poi, sia per il debug sia per gli ordinamenti. L’helper timestamps() crea le due colonne in un colpo solo, nullable:
php artisan make:migration add_timestamps_to_reports_table --table=reportspublic function up(): void
{
Schema::table('reports', function (Blueprint $table) {
$table->timestamps();
});
}
public function down(): void
{
Schema::table('reports', function (Blueprint $table) {
$table->dropTimestamps();
});
}php artisan migrateDopo la migration l’inserimento passa e le date sono valorizzate. Verificato: la tabella contiene id, title, created_at, updated_at e $report->created_at restituisce un’istanza di Illuminate\Support\Carbon, che puoi formattare e confrontare.
Su una tabella che contiene già delle righe, le colonne vengono create a NULL sull’esistente, e non è un problema. Se invece vuoi un valore, dichiaralo esplicitamente:
$table->timestamp('created_at')->nullable()->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrent()->useCurrentOnUpdate();Soluzione 2: disattivare i timestamp sul modello
Quando la tabella non ha motivo di portarsi dietro queste date, tabella di collegamento, tabella di riferimento congelata, schema imposto da un sistema esterno, dillo al modello:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
public $timestamps = false;
}Eloquent smette di valorizzare le due colonne e l’inserimento funziona. Puoi controllare lo stato con $video->usesTimestamps(), che restituisce false.
La stessa disattivazione si può fare una volta sola su un’istanza, per esempio per correggere un dato senza toccare updated_at:
$task->timestamps = false;
$task->title = 'Titre corrigé';
$task->save(); // updated_at resta invariatoSe la tabella dovrebbe avere queste colonne, $timestamps = false non risolve niente: toglie un’informazione che cercherai più avanti. Tieni questa soluzione per le tabelle in cui la data di modifica non ha davvero senso.
Soluzione 3: le colonne esistono ma con un altro nome
Su un database ereditato le colonne si chiamano spesso date_creation, creation_date o modified_on. Non serve rinominare nulla: dichiara a Eloquent i nomi reali con due costanti.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Clip extends Model
{
const CREATED_AT = 'creation_date';
const UPDATED_AT = 'updated_date';
}Da qui in avanti Eloquent scrive in quelle colonne. Verificato su Laravel 13: dopo Clip::create(['title' => 'Extrait']) la colonna creation_date contiene l’orario, e getUpdatedAtColumn() restituisce updated_date.
Se esiste una sola delle due date, metti l’altra a null:
const CREATED_AT = 'creation_date';
const UPDATED_AT = null; // nessuna colonna di aggiornamentoGli accessor $clip->created_at e $clip->updated_at, invece, non seguono queste costanti: restituiscono null. Leggete la colonna con il suo vero nome, $clip->creation_date, o in modo generico con $clip->{$clip->getCreatedAtColumn()}.
Quale soluzione scegliere
| Situazione | Soluzione |
|---|---|
| Tabella applicativa normale, colonne semplicemente dimenticate | Aggiungere le colonne con una migration |
| Tabella pivot, tabella di riferimento congelata, schema imposto | public $timestamps = false; |
| Database ereditato con colonne di date chiamate diversamente | Costanti CREATED_AT e UPDATED_AT |
Una singola scrittura non deve toccare updated_at | $model->timestamps = false; prima di save() |
Errori frequenti
$timestamps = false elimina un'informazione utile invece di correggere lo schema. Meglio aggiungere le colonne.timestamps() le crea nullable, e passa. Una definizione NOT NULL senza valore predefinito farebbe fallire la migration.

