
Eloquent schreibt bei jedem Insert created_at und updated_at mit: Der Fehler bedeutet, dass die Tabelle diese Spalten nicht hat. Je nach Fall gibt es drei Korrekturen: Ergänze sie per Migration mit $table->timestamps(), schalte sie im Model mit public $timestamps = false; ab, oder deklariere ihre echten Namen über die Konstanten CREATED_AT und UPDATED_AT.
Die Meldung erscheint beim ersten save() oder create() auf einem Model:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'INSERT INTO'Die Ursache ist immer dieselbe: Eloquent pflegt zwei Datumsspalten, created_at und updated_at, und schreibt sie bei jedem Insert und jedem Update mit. Fehlen sie in der Tabelle, scheitert die Query. Es gibt drei Wege, das zu beheben, und der richtige hängt von der Tabelle ab, nicht von deinem Geschmack.
Erschienen im Themenpfad Webentwicklung. Fehler reproduziert und Korrekturen geprüft auf Laravel 13.30.1 mit MariaDB 11.8.9.
Den Fehler erkennen
Der Wortlaut hängt von der Datenbank und von der Operation ab, nennt aber immer updated_at oder 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_atSieh zuerst nach, was in der Tabelle tatsächlich steht:
php artisan tinker --execute='echo implode(", ", Schema::getColumnListing("reports"));'id, titleFehlen created_at und updated_at, lies weiter. Gibt es sie unter einem anderen Namen, spring direkt zur dritten Lösung.
Lösung 1: die Spalten ergänzen
Das vollständige Vorgehen beschreibt der Leitfaden zu den Laravel-Migrationen.
In den meisten Fällen ist das die richtige Antwort. Zu wissen, wann eine Zeile angelegt und wann sie geändert wurde, brauchst du früher oder später ohnehin, beim Debuggen wie beim Sortieren. Der Helper timestamps() legt beide Spalten auf einen Schlag an, 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 migrateNach der Migration läuft das Insert durch und die Daten stehen drin. Geprüft: Die Tabelle enthält id, title, created_at, updated_at, und $report->created_at liefert eine Instanz von Illuminate\Support\Carbon, die du formatieren und vergleichen kannst.
Enthält die Tabelle bereits Zeilen, werden die Spalten dort mit NULL angelegt, was unproblematisch ist. Willst du einen Wert, gibst du ihn explizit an:
$table->timestamp('created_at')->nullable()->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrent()->useCurrentOnUpdate();Lösung 2: die Timestamps im Model abschalten
Soll die Tabelle diese Daten gar nicht führen, etwa eine Verknüpfungstabelle, feste Stammdaten oder ein von einem Fremdsystem vorgegebenes Schema, dann sag es dem Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
public $timestamps = false;
}Eloquent füllt die beiden Spalten daraufhin nicht mehr, und das Insert funktioniert. Bestätigen lässt sich der Zustand mit $video->usesTimestamps(), das false zurückgibt.
Dieselbe Abschaltung geht punktuell auf einer einzelnen Instanz, etwa um einen Wert zu korrigieren, ohne updated_at anzufassen:
$task->timestamps = false;
$task->title = 'Titre corrigé';
$task->save(); // updated_at bleibt unverändertSollte die Tabelle diese Spalten eigentlich haben, löst $timestamps = false gar nichts: Es nimmt dir eine Information weg, die du später suchen wirst. Nimm diese Lösung nur für Tabellen, bei denen ein Änderungsdatum wirklich keinen Sinn ergibt.
Lösung 3: die Spalten heißen anders
In einer Altdatenbank heißen die Spalten oft date_creation, creation_date oder modified_on. Umbenennen musst du deshalb nichts: Nenne Eloquent über zwei Konstanten die echten Namen.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Clip extends Model
{
const CREATED_AT = 'creation_date';
const UPDATED_AT = 'updated_date';
}Eloquent schreibt ab jetzt in diese Spalten. Geprüft auf Laravel 13: Nach Clip::create(['title' => 'Extrait']) steht der Zeitstempel in creation_date, und getUpdatedAtColumn() liefert updated_date.
Existiert nur eine der beiden Datumsspalten, setzt du die andere auf null:
const CREATED_AT = 'creation_date';
const UPDATED_AT = null; // keine Spalte für die AktualisierungDie Accessoren $clip->created_at und $clip->updated_at folgen diesen Konstanten dagegen nicht: Sie liefern null. Lesen Sie die Spalte unter ihrem echten Namen, $clip->creation_date, oder generisch mit $clip->{$clip->getCreatedAtColumn()}.
Welche Lösung wann
| Situation | Lösung |
|---|---|
| Normale Anwendungstabelle, Spalten schlicht vergessen | Spalten per Migration ergänzen |
| Pivot-Tabelle, feste Stammdaten, vorgegebenes Schema | public $timestamps = false; |
| Altdatenbank mit anders benannten Datumsspalten | Konstanten CREATED_AT und UPDATED_AT |
Ein einzelner Schreibvorgang darf updated_at nicht anfassen | $model->timestamps = false; vor save() |
Häufige Fehler
$timestamps = false eine nützliche Information, statt das Schema zu korrigieren. Ergänze lieber die Spalten.timestamps() legt sie nullable an, das läuft durch. Eine NOT-NULL-Definition ohne Standardwert würde die Migration scheitern lassen.

