Bases de la sécurité
Supabase PGRST204: "Could not find the column in the schema cache"
Supabase "Could not find the column in the schema cache" vient le plus souvent du nom. Quatre vérifications, et la ligne qui recharge le cache.

En bref
- Supabase "Could not find the column in the schema cache" (PGRST204) signifie que votre application a voulu enregistrer un champ que la table ne répertorie pas. PostgREST compare chaque clé d'un insert ou d'un update à sa propre copie de votre schéma, lettre par lettre.
- La cause habituelle est le nom : phoneNumber envoyé à une colonne appelée phone_number, ou une clé qui n'a jamais été une colonne, comme des lignes liées imbriquées dans un insert.
- Supabase recharge cette copie tout seul dès qu'une table change. Quand elle est vraiment périmée, NOTIFY pgrst, 'reload schema'; dans le SQL Editor la recharge pendant que l'application continue de tourner.
Vous avez demandé à votre builder d'ajouter un numéro de téléphone au formulaire de profil. La colonne apparaît dans le Table Editor. Vous cliquez sur Enregistrer, rien ne se passe, et la console du navigateur affiche ceci :
{
"code": "PGRST204",
"details": null,
"hint": null,
"message": "Could not find the 'phoneNumber' column of 'profiles' in the schema cache"
}
Supabase "Could not find the column in the schema cache" signifie que votre
application a voulu enregistrer un champ que la table, telle que PostgREST la
voit, n'a pas. PostgREST est la partie de Supabase qui transforme les appels
supabase.from(...) de votre application en requêtes à la base de données. Il
tient sa propre liste de chaque table et de chaque colonne, appelée cache de
schéma, pour ne pas avoir à interroger la base sur sa structure à chaque requête.
Voici le point sur lequel la plupart des réponses se trompent : elles vous disent de recharger le cache de schéma. Sur Supabase, le cache se recharge tout seul à chaque fois qu'une table change. Si vous venez d'ajouter une colonne et que vous voyez encore cette erreur, le cache est donc la raison la moins probable. Le nom l'est le plus souvent.
Que signifie "Could not find the column in the schema cache" ?
Une clé d'une écriture envoyée par votre application n'a pas de colonne correspondante dans cette table.
Imaginez le cache de schéma comme le tableau d'affichage dans le hall d'un immeuble : une ligne pour chaque bureau, c'est-à-dire chaque table, et en dessous chaque pièce, c'est-à-dire chaque colonne. Chaque requête de votre application est un bon de livraison. PostgREST lit chaque ligne du bon face au tableau, et une pièce que le tableau ne mentionne pas est refusée à l'accueil, avant que quoi que ce soit n'atteigne vos données.
Le message nomme les deux côtés de cette comparaison. Dans Could not find the 'phoneNumber' column of 'profiles' in the schema cache, phoneNumber est ce
que votre application a envoyé et profiles la table à laquelle c'était
destiné. Trois autres choses sont fixées dans
le code de PostgREST lui-même :
- le code est
PGRST204et le statut HTTP 400, ce qui veut dire que la requête elle-même était fausse - il vient uniquement des écritures :
.insert(),.update()et.upsert(). Une lecture qui nomme une colonne absente échoue avec une autre erreur, écrite par Postgres - il ne donne aucune piste. Pour une
table absente, PostgREST suggère le
nom le plus proche qu'il connaît ; pour une colonne absente,
hintvautnull, et la comparaison vous revient
Chaque clé de l'objet que vous passez à l'un de ces trois appels doit être une colonne de cette table, écrite comme la table l'écrit.
Cause 1 : le nom ne correspond pas, lettre par lettre
La vérification est exacte. Pour PostgREST, phoneNumber, phone_number et
phonenumber sont trois colonnes différentes, et votre table en a au plus une.
Il y a deux façons courantes d'en arriver là. La première, ce sont deux habitudes
de nommage qui se rencontrent : JavaScript écrit généralement un champ
phoneNumber, et une colonne Postgres s'appelle généralement phone_number. Le
code écrit par votre builder et le SQL qu'il a exécuté peuvent chacun être
justes de leur côté et quand même se contredire.
La seconde, c'est le piège des guillemets. En SQL, un nom tapé sans guillemets doubles est converti en minuscules. La documentation de Postgres le dit clairement : "Quoting an identifier also makes it case-sensitive, whereas unquoted names are always folded to lower case."
| Ce que vous avez exécuté dans le SQL Editor | La colonne créée | Ce que votre application doit envoyer |
|---|---|---|
alter table profiles add column phone_number text; | phone_number | phone_number |
alter table profiles add column phoneNumber text; | phonenumber | phonenumber |
alter table profiles add column "phoneNumber" text; | phoneNumber | phoneNumber |
C'est la ligne du milieu qui piège les gens. Le SQL a l'air d'avoir créé
phoneNumber, le code envoie phoneNumber, et la colonne s'appelle
phonenumber.
Pour voir les vrais noms, ouvrez la table dans le Table Editor et lisez les en-têtes de colonnes, ou exécutez ceci dans le SQL Editor :
select column_name
from information_schema.columns
where table_schema = 'public' and table_name = 'profiles';
Regardez ensuite ce que votre application a envoyé. Dans les outils de
développement de votre navigateur, ouvrez l'onglet Réseau (Network), cliquez
sur la requête échouée vers /rest/v1/profiles et lisez sa charge utile.
La correction la plus sûre est de modifier l'application, parce que cela ne
touche à rien dans vos données. Demandez à votre builder d'utiliser le nom exact
de la colonne partout où ce champ est enregistré : "la colonne de profiles
s'appelle phone_number ; utilise ce nom dans chaque insert et chaque update".
Renommer la colonne à la place, c'est modifier une table en service, et tout
autre écran qui utilise encore l'ancien nom casse la première fois qu'il
s'exécute.
Si vous construisez avec Lovable, remontez le chat à la recherche d'une modification de base de données que vous deviez approuver. La documentation Supabase de Lovable dit qu'il "writes the SQL, shows it to you, and asks for your approval in the project chat before running it". Tant que vous ne l'avez pas approuvée, la colonne n'existe pas, quoi qu'attende le code.
Cause 2 : une clé qui n'a jamais été une colonne
La requête contient quelque chose que la table n'a jamais été censée stocker : des lignes liées imbriquées dans l'insert, ou un champ que le formulaire garde pour lui.
L'insert imbriqué est celui dont on attend qu'il fonctionne :
await supabase.from('orders').insert({
customer_id: user.id,
total: 42,
order_items: [{ product_id: 7, quantity: 2 }],
})
Cela échoue avec Could not find the 'order_items' column of 'orders' in the schema cache. Lire la même forme fonctionne : .select('*, order_items(*)')
renvoie une commande avec ses articles, donc le sens inverse a l'air de devoir
marcher aussi. PostgREST lit chaque clé d'une écriture comme une colonne de la
seule table visée par la requête. Un utilisateur de Supabase
l'a signalé comme un bug,
et la réponse, avant la fermeture de l'issue le 18 octobre 2026, était que les
inserts imbriqués sont une fonctionnalité manquante. La demande est ouverte sur
le suivi de PostgREST depuis
février 2017.
Deux autres formes du même problème :
- une ligne lue avec ses lignes liées, modifiée dans un formulaire et renvoyée
telle quelle dans
.update(), si bien que leorder_itemsou leprofilesattaché part avec elle - l'état complet d'un formulaire passé directement à
.insert(), avec des champs dont le formulaire a besoin et pas la table, commeconfirmPassword
La correction consiste à écrire chaque table séparément, le parent d'abord.
Insérez la commande et demandez son id en retour avec .select('id').single(),
puis insérez les articles avec ce order_id. Ce sont deux requêtes : si la
seconde échoue, la commande reste enregistrée sans ses articles. Quand cela ne
doit jamais arriver, mettez les deux inserts dans une fonction Postgres et
appelez-la avec .rpc(), ce que la réponse sur cette issue appelle la méthode
standard. Alors tout est enregistré, ou rien. Si cet appel répond PGRST202 à la
place, la version fonction de cette erreur
explique pourquoi.
Cause 3 : la modification est partie dans un autre projet
La colonne existe, dans une base de données à laquelle votre application ne parle jamais. Un compte Supabase peut contenir plusieurs projets, et une branche est un projet à part avec sa propre base. Une colonne ajoutée dans le SQL Editor du mauvais modifie le tableau d'un autre immeuble.
Sur l'issue #42183 de Supabase, un signalement selon lequel le cache "does not update" quoi qu'on essaie, l'un des développeurs de PostgREST a répondu que le signalement citait deux références de projet différentes, et a demandé de confirmer que la modification avait été faite dans le projet auquel les requêtes étaient envoyées.
La vérification tient en deux adresses. Votre application appelle
https://<reference>.supabase.co, ce que vous voyez sur n'importe quelle
requête dans l'onglet Réseau. Le tableau de bord affiche le projet où vous êtes à
l'adresse supabase.com/dashboard/project/<reference>. Les deux références
doivent être la même chaîne.
Quel projet est le mien explique comment
le retrouver quand quelqu'un d'autre a configuré Supabase.
Cause 4 : le cache est vraiment périmé
C'est le cas rare sur Supabase, parce que Supabase recharge le cache pour vous.
Chaque base Supabase est configurée avec un déclencheur d'événement,
pgrst_ddl_watch, qui s'exécute après chaque changement de structure de la
base, ALTER TABLE compris, et envoie NOTIFY pgrst, 'reload schema' : le
message qui dit à PostgREST de reconstruire sa liste. Vous pouvez le lire dans
la configuration de base de Supabase.
Ajouter une colonne dans le Table Editor ou le SQL Editor repeint le tableau
tout seul.
Ça se passe mal quand ce message n'arrive jamais. Le
guide de dépannage
de Supabase décrit le cas : "an underlying Postgres notification queue issue
prevents PostgREST from receiving cache reload signals after schema changes".
Le journal de PostgREST affiche alors Failed listening for database notifications on the "pgrst" channel, et le tableau reste tel quel, peu importe
le nombre de colonnes que vous ajoutez.
Comment recharger le cache de schéma de Supabase ?
Exécutez une ligne dans le SQL Editor :
NOTIFY pgrst, 'reload schema';
La page de Supabase à ce sujet indique que vous devriez voir "Success. No rows returned" sous Results. C'est sans risque sur une application en service. La documentation de PostgREST dit "Requests will wait until the schema cache reload is done", donc personne qui utilise l'application ne voit d'erreur pendant ce temps.
Si la file de notifications est le problème, le message de rechargement reste bloqué de la même façon que le message automatique. Le guide de dépannage donne une seconde ligne pour ce cas :
select pg_notification_queue_usage();
Selon Supabase, elle pousse PostgREST à mettre à jour son cache et "does not require a database instance or PostgREST service restart". Réessayez ensuite d'enregistrer.
Quand le rechargement ne suffit pas
Redémarrez le projet, et si l'erreur survit à cela, revenez aux causes 1 à 3.
Un redémarrage donne toujours à PostgREST une liste neuve. Le même développeur de PostgREST a écrit sur #42183 qu'un PostgREST redémarré "won't go live if it doesn't load a new schema cache". Restart project se trouve dans Project Settings, puis General, et comment redémarrer un projet Supabase vous guide, y compris pour les quelques minutes où il est hors ligne.
Une erreur qui survit à un redémarrage vient donc d'une liste neuve et exacte : cette table, dans ce projet, n'a pas de colonne de ce nom. #42183 lui-même, ouvert en janvier 2026 par quelqu'un qui avait essayé un rechargement, un redémarrage, puis la suppression et le réajout de la colonne, était toujours ouvert quand nous l'avons lu le 21 octobre 2026. La réponse du développeur y suggérait aussi de passer à PostgREST 14 depuis les réglages Infrastructure du projet.
Rayez supprimer et réajouter de votre liste. alter table … drop column efface
chaque valeur stockée dans cette colonne, et la nouvelle colonne du même nom
démarre vide. Si vous êtes sur le point de modifier une table dans laquelle de
vrais utilisateurs écrivent, gardez une copie de la base d'avant le changement.
Reeve Care en fait une selon un calendrier et la conserve
chiffrée, sur le stockage propre de Reeve dans l'UE.
Garder vos types générés à jour
Régénérez vos types TypeScript après chaque modification d'une table, et un nom de colonne mal écrit peut apparaître dans l'éditeur avant d'atteindre le site en ligne.
Supabase construit le fichier à partir de vos vraies colonnes, soit depuis le tableau de bord, soit avec une commande tirée de son guide de génération des types :
npx supabase gen types typescript --project-id "$PROJECT_REF" --schema public > database.types.ts
Quand le client est créé avec ces types, createClient<Database>(…), le type
Insert de chaque table liste les colonnes que .insert() accepte. Une colonne
mal écrite dans un objet écrit en entier dans l'appel est alors signalée comme
une erreur avant que vous ne publiiez. La documentation de Lovable dit qu'il
"regenerates the TypeScript types your app uses" après une modification de base.
Un fichier de types généré avant votre dernière modification de la table liste
encore les anciennes colonnes.
Modifier une table en service sans perdre ce qu'elle contient
Gardez une copie d'avant le changement, et sachez tout de suite si l'application répond encore après.
Reeve Care garde une copie de votre base Supabase :
- une copie chiffrée selon un calendrier, sur le stockage propre de Reeve dans l'UE, en dehors de votre compte Supabase
- la dernière copie avant votre changement contient les tables et les colonnes telles qu'elles étaient, lignes comprises
- chaque copie vérifiée avant de compter, en comptant les lignes de chaque table
- vos fichiers envoyés aussi, dès que vous connectez un identifiant Storage
- une restauration en un clic, avec une copie de sécurité de l'état actuel prise d'abord
- tout ce que fait Monitor
Reeve Monitor continue de vérifier depuis l'extérieur :
- si votre application répond, vérifié chaque minute, pour distinguer facilement un bouton Enregistrer cassé d'une panne
- le contrôle de sécurité complet toutes les heures, sur trois applications au plus
- un message quand un résultat change, pour qu'un déploiement qui modifie ce que votre application expose vous parvienne sans que vous alliez voir
- un rapport mensuel, en langage clair, de ce qu'il a vu
Que faire maintenant
Que faire
- Lisez les deux noms du message : la clé envoyée par votre application et la table à laquelle elle était destinée.
- Comparez cette clé à la colonne dans le Table Editor, lettre par lettre. Un nom tapé en SQL sans guillemets est enregistré en minuscules.
- Cherchez les clés qui ne sont pas des colonnes : des lignes liées imbriquées dans un insert, ou une ligne entière renvoyée avec ses lignes liées. Écrivez chaque table séparément, ou mettez les deux écritures dans une fonction.
- Vérifiez que la référence dans l'adresse Supabase de votre application correspond au projet que vous avez modifié.
- Si tout cela correspond, exécutez
NOTIFY pgrst, 'reload schema';, puisselect pg_notification_queue_usage();, et ne redémarrez le projet que si aucun des deux n'aide. - Régénérez vos types TypeScript après chaque modification d'une table.
Commencez par le nom de colonne que cite le message, parce que c'est exactement ce que votre application a envoyé, et le Table Editor montre exactement ce que la table contient. Avant de renommer ou de supprimer quoi que ce soit dans une table que des gens utilisent, gardez une copie de la base d'avant le changement.
FAQ
Que signifie PGRST204 ?
PGRST204 est le code que PostgREST, la partie de Supabase qui répond aux appels de votre application à la base de données, donne à une écriture qui nomme une colonne que la table n'a pas. Il revient avec HTTP 400 et le message "Could not find the 'x' column of 'y' in the schema cache", où x est la clé envoyée par votre application et y la table visée. Les insert, update et upsert le produisent.
J'ai ajouté la colonne et ça échoue encore. Pourquoi ?
Le plus souvent, à cause du nom. Vérifiez que votre application envoie exactement le nom enregistré (une colonne ajoutée en SQL sous le nom phoneNumber, sans guillemets, est enregistrée sous phonenumber), que vous l'avez ajoutée dans le projet que votre application appelle, et que rien d'autre dans la requête n'est une clé que la table ne connaît pas. Supabase recharge le cache de schéma tout seul après chaque ALTER TABLE, donc un cache périmé est la dernière chose à soupçonner.
Comment recharger le cache de schéma de Supabase ?
Exécutez NOTIFY pgrst, 'reload schema'; dans le SQL Editor. Si rien ne change, le guide de dépannage de Supabase donne une seconde commande, select pg_notification_queue_usage();, pour le cas où les messages de rechargement restent bloqués. Les requêtes qui arrivent pendant le rechargement attendent qu'il soit terminé.
Mettre le projet en pause vide-t-il le cache ?
Oui. PostgREST construit un cache de schéma neuf à chaque démarrage, et la reprise d'un projet en pause le redémarre. Restart project, dans Project Settings puis General, fait la même chose sans la pause. Si l'erreur survit à l'un ou à l'autre, le cache avait raison depuis le début : la colonne manque dans cette table, dans ce projet.
Pourquoi les inserts imbriqués échouent-ils avec cette erreur ?
Parce que PostgREST lit chaque clé d'un insert comme une colonne d'une seule table, et une clé qui contient des lignes liées est une colonne qu'il ne trouve pas. Lire des lignes liées en une requête fonctionne, les écrire de cette façon n'a jamais été pris en charge. Insérez d'abord le parent, puis les enfants avec son id, ou faites les deux dans une fonction Postgres appelée avec rpc().