Corriger l’erreur Laravel « Unknown column ‘updated_at’ »

Introduction L’ORM Eloquent inclus avec Laravel vous fournit un moyen facile d’interagir avec votre base de données. Cela simplifie toutes les opérations CRUD (Create, read, update, and delete) et toute autre requête de base de données. Comme décrit dans le document officiel Documentation Laravel, Eloquent s’attend à ce que le created_at et updated_at doivent exister

Corriger l’erreur Laravel « Unknown column ‘updated_at’ »
Réponse rapide

Eloquent écrit created_at et updated_at à chaque insertion : l’erreur signifie que la table ne les possède pas. Trois correctifs selon le cas : ajoutez-les par migration avec $table->timestamps(), désactivez-les avec public $timestamps = false; sur le modèle, ou déclarez leurs vrais noms avec les constantes CREATED_AT et UPDATED_AT.

Le message tombe au premier save() ou create() sur un modèle :

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

La cause est toujours la même : Eloquent tient à jour deux colonnes de dates, created_at et updated_at, et les écrit à chaque insertion ou mise à jour. Si la table ne les possède pas, la requête échoue. Il y a trois façons de régler ça, et le bon choix dépend de la table, pas de vos préférences.

Article du parcours Développement web. Erreur reproduite et correctifs vérifiés sur Laravel 13.30.1 avec MariaDB 11.8.9.

Reconnaître l’erreur

Le libellé varie selon le moteur et l’opération, mais il désigne toujours 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

Vérifiez d’abord ce que contient réellement la table :

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

Si created_at et updated_at manquent, passez à la suite. Si elles sont présentes sous un autre nom, allez directement à la troisième solution.

Solution 1 : ajouter les colonnes

La marche à suivre complète est décrite dans le guide des migrations Laravel.

C’est la bonne réponse dans la plupart des cas. Savoir quand une ligne a été créée et modifiée sert tôt ou tard, au débogage comme au tri. Le helper timestamps() crée les deux colonnes d’un coup, nullables :

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

Après la migration, l’insertion passe et les dates sont renseignées. Vérifié : la table contient bien id, title, created_at, updated_at et $report->created_at renvoie une instance de Illuminate\Support\Carbon, que vous pouvez formater et comparer.

Pour une table qui contient déjà des lignes, les colonnes sont créées à NULL sur l’existant, ce qui ne pose pas de problème. Si vous voulez une valeur, ajoutez-la explicitement :

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

Solution 2 : désactiver les timestamps sur le modèle

Quand la table n’a pas vocation à porter ces dates, table de liaison, référentiel figé ou schéma imposé par un système tiers, dites-le au modèle :

app/Models/Video.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

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

Eloquent cesse alors de renseigner les deux colonnes, et l’insertion fonctionne. Vous pouvez confirmer l’état avec $video->usesTimestamps(), qui renvoie false.

La même désactivation peut se faire ponctuellement sur une instance, par exemple pour corriger une donnée sans modifier updated_at :

php
$task->timestamps = false;
$task->title = 'Titre corrigé';
$task->save();   // updated_at reste inchangé
Ne désactivez pas pour faire taire l’erreur

Si la table devrait avoir ces colonnes, $timestamps = false ne règle rien : il enlève une information que vous chercherez plus tard. Réservez cette solution aux tables où la date de modification n’a réellement pas de sens.

Solution 3 : les colonnes existent sous un autre nom

Sur une base héritée, les colonnes s’appellent souvent date_creation, creation_date ou modified_on. Inutile de renommer quoi que ce soit : indiquez à Eloquent les noms réels avec deux 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';
}

Eloquent écrit désormais dans ces colonnes. Vérifié sur Laravel 13 : après Clip::create(['title' => 'Extrait']), la colonne creation_date contient bien l’horodatage, et getUpdatedAtColumn() renvoie updated_date.

Si une seule des deux dates existe, mettez l’autre à null :

php
const CREATED_AT = 'creation_date';
const UPDATED_AT = null;   // aucune colonne de mise à jour

Les accesseurs $clip->created_at et $clip->updated_at, eux, ne suivent pas ces constantes : ils renvoient null. Lisez la colonne par son vrai nom, $clip->creation_date, ou de façon générique avec $clip->{$clip->getCreatedAtColumn()}.

Quelle solution retenir

Situation Solution
Table applicative normale, colonnes simplement oubliées Ajouter les colonnes par migration
Table pivot, référentiel figé, schéma imposé public $timestamps = false;
Base héritée avec des colonnes de dates nommées autrement Constantes CREATED_AT et UPDATED_AT
Une seule écriture ne doit pas toucher updated_at $model->timestamps = false; avant save()

Erreurs fréquentes

Désactiver les timestamps pour faire taire l’erreur Sur une table applicative normale, $timestamps = false supprime une information utile au lieu de corriger le schéma. Ajoutez plutôt les colonnes.
Colonnes NOT NULL sur une table déjà remplie timestamps() les crée nullables, ce qui passe. Une définition NOT NULL sans valeur par défaut ferait échouer la migration.
Renommer les colonnes de la base héritée Inutile et risqué : les constantes CREATED_AT et UPDATED_AT suffisent à pointer vers les noms existants.
Oublier UPDATED_AT = null Si la table n’a qu’une colonne de création, laisser UPDATED_AT par défaut relance la même erreur à la mise à jour.

EloquentLaravelMigrationsPHP

Damien Flandrin Développeur web depuis 2010, créateur de Gekkode et d’Email Impact. Chaque article est testé sur un projet réel avant publication. Contact
Newsletter

Les nouveaux tests, tutoriels et projets, par e-mail.

Tests reproductibles, code versionné, résultats datés. Jamais de spam.