
Eloquent schrijft bij elke insert created_at en updated_at weg: de fout betekent dat je tabel ze niet heeft. Drie oplossingen, afhankelijk van het geval: voeg ze toe met een migratie via $table->timestamps(), schakel ze uit met public $timestamps = false; op het model, of geef hun echte namen op met de constanten CREATED_AT en UPDATED_AT.
De melding valt bij de eerste save() of create() op een model:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'INSERT INTO'De oorzaak is altijd dezelfde: Eloquent houdt twee datumkolommen bij, created_at en updated_at, en schrijft ze bij elke insert en elke update weg. Heeft de tabel ze niet, dan faalt de query. Er zijn drie manieren om dit op te lossen, en welke de juiste is hangt af van de tabel, niet van je voorkeur.
Artikel uit het leertraject Webontwikkeling. Fout gereproduceerd en oplossingen gecontroleerd op Laravel 13.30.1 met MariaDB 11.8.9.
De fout herkennen
De formulering verschilt per database en per operatie, maar het gaat altijd over updated_at of 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_atKijk eerst wat er werkelijk in de tabel staat:
php artisan tinker --execute='echo implode(", ", Schema::getColumnListing("reports"));'id, titleOntbreken created_at en updated_at, ga dan verder met de volgende stap. Staan ze er wel, maar onder een andere naam, spring dan meteen naar de derde oplossing.
Oplossing 1: de kolommen toevoegen
De volledige werkwijze staat in de gids over migraties in Laravel.
Dit is in de meeste gevallen het juiste antwoord. Weten wanneer een rij is aangemaakt en gewijzigd komt vroeg of laat van pas, bij het debuggen net zo goed als bij het sorteren. De helper timestamps() maakt beide kolommen in één keer aan, 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 migrateNa de migratie gaat de insert door en worden de datums gevuld. Gecontroleerd: de tabel bevat inderdaad id, title, created_at, updated_at en $report->created_at geeft een instantie van Illuminate\Support\Carbon terug, die je kunt formatteren en vergelijken.
Staat er al data in de tabel, dan komen de kolommen op NULL te staan voor de bestaande rijen, en dat is geen probleem. Wil je toch een waarde, zet die er dan expliciet in:
$table->timestamp('created_at')->nullable()->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrent()->useCurrentOnUpdate();Oplossing 2: de timestamps op het model uitschakelen
Hoort de tabel die datums helemaal niet te dragen, denk aan een koppeltabel, een bevroren referentielijst of een schema dat een extern systeem oplegt, zeg dat dan tegen het model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
public $timestamps = false;
}Eloquent vult die twee kolommen daarna niet meer, en de insert werkt. Je bevestigt de stand met $video->usesTimestamps(), dat false teruggeeft.
Diezelfde uitschakeling kan ook eenmalig op één instantie, bijvoorbeeld om een waarde recht te zetten zonder updated_at aan te raken:
$task->timestamps = false;
$task->title = 'Titre corrigé';
$task->save(); // updated_at blijft ongewijzigdHoort de tabel die kolommen te hebben, dan lost $timestamps = false niets op: het haalt informatie weg waar je later naar op zoek gaat. Houd deze oplossing voor tabellen waar een wijzigingsdatum werkelijk geen betekenis heeft.
Oplossing 3: de kolommen bestaan onder een andere naam
In een gegroeide database heten de kolommen vaak date_creation, creation_date of modified_on. Hernoemen hoeft niet: geef Eloquent de echte namen door met twee constanten.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Clip extends Model
{
const CREATED_AT = 'creation_date';
const UPDATED_AT = 'updated_date';
}Eloquent schrijft voortaan in die kolommen. Gecontroleerd op Laravel 13: na Clip::create(['title' => 'Extrait']) staat het tijdstip netjes in de kolom creation_date, en getUpdatedAtColumn() geeft updated_date terug.
Bestaat maar een van de twee datums, zet de andere dan op null:
const CREATED_AT = 'creation_date';
const UPDATED_AT = null; // geen kolom voor de laatste wijzigingDe accessors $clip->created_at en $clip->updated_at volgen deze constanten daarentegen niet: ze geven null terug. Lees de kolom onder haar echte naam, $clip->creation_date, of generiek met $clip->{$clip->getCreatedAtColumn()}.
Welke oplossing kies je
| Situatie | Oplossing |
|---|---|
| Gewone applicatietabel, kolommen simpelweg vergeten | De kolommen toevoegen met een migratie |
| Pivottabel, bevroren referentielijst, opgelegd schema | public $timestamps = false; |
| Gegroeide database met anders genoemde datumkolommen | De constanten CREATED_AT en UPDATED_AT |
Eén schrijfactie mag updated_at niet aanraken | $model->timestamps = false; vóór save() |
Veelgemaakte fouten
$timestamps = false nuttige informatie weg in plaats van je schema te repareren. Voeg liever de kolommen toe.timestamps() maakt ze nullable, en dat gaat goed. Een definitie met NOT NULL zonder standaardwaarde laat de migratie stuklopen.

