Bases de la sécurité
Supabase PGRST202: "Could not find the function in the schema cache"
Supabase "Could not find the function in the schema cache" cite les noms d'arguments envoyés par votre application. Comparez-les à la fonction.

En bref
- Supabase "Could not find the function in the schema cache" (PGRST202) signifie qu'aucune fonction ne porte ce nom en acceptant exactement les noms d'arguments que votre application a envoyés. Les noms entre parenthèses dans le message sont ceux que votre application a envoyés.
- Vérifiez d'abord les noms d'arguments : userId envoyé à une fonction qui déclare user_id, un préfixe p_ oublié, ou une valeur restée undefined et donc jamais envoyée.
- Supabase met à jour sa liste de fonctions tout seul dès qu'une fonction est créée, modifiée ou supprimée. Vérifiez donc les noms et le schéma avant de recharger quoi que ce soit.
Votre builder a écrit une fonction de base de données qui charge les commandes d'un client, et la page qui l'appelle reste vide. La console du navigateur affiche ceci :
{
"code": "PGRST202",
"details": "Searched for the function public.get_orders with parameter userId or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache.",
"hint": "Perhaps you meant to call the function public.get_orders(user_id)",
"message": "Could not find the function public.get_orders(userId) in the schema cache"
}
Supabase "Could not find the function in the schema cache" signifie que PostgREST
n'a aucune fonction de ce nom qui accepte exactement les arguments envoyés par
votre application. PostgREST est la partie de Supabase qui répond aux appels
supabase.rpc() de votre application, et il tient sa propre liste de toutes les
fonctions qu'il peut appeler, appelée cache de schéma.
Voici le point sur lequel la plupart des réponses se trompent : elles vous
disent de recharger le cache de schéma. Sur Supabase, cette liste se met à jour toute
seule dès qu'une fonction est créée ou modifiée. Le message vous a déjà dit ce qui
ne va pas. userId, entre parenthèses, est ce que votre application a envoyé.
user_id, dans l'indice, est ce que la fonction attend.
Que signifie "Could not find the function in the schema cache" ?
Aucune fonction du schéma que PostgREST a parcouru ne porte ce nom avec exactement ces noms d'arguments.
Imaginez chaque fonction de la base comme un formulaire imprimé épinglé derrière un
guichet : son nom en haut, et une case légendée par argument. Quand votre
application appelle supabase.rpc('get_orders', { userId: id }), elle tend une
copie remplie. PostgREST cherche au mur un formulaire qui a le même nom et les
mêmes légendes. Si aucun ne les a, la copie est refusée au guichet, et le message
vous relit les légendes que vous avez remplies.
Quatre détails sont fixés dans le code de PostgREST :
- le code est
PGRST202et le statut HTTP 404, celui d'une page qui n'existe pas - les parenthèses listent les noms d'arguments que votre application a envoyés.
Quand elle n'en a envoyé aucun, le message dit
without parametersà leur place public.devant le nom est le schéma que PostgREST a parcouru- l'indice, quand il y en a un, nomme la fonction la plus proche que PostgREST connaît, avec ses propres noms d'arguments
Comparez les parenthèses avec l'indice avant toute autre chose.
Cause 1 : les noms d'arguments ne correspondent pas
PostgREST choisit une fonction par son nom et ses noms d'arguments pris ensemble. Une fonction appelée avec les mauvais noms est donc, pour PostgREST, une fonction qui n'existe pas.
Les règles, tirées de la recherche dans le planificateur de PostgREST :
- chaque argument sans valeur par défaut doit être envoyé, sous son nom exact
- un argument qui a une valeur par défaut peut être omis
- un nom que la fonction ne déclare pas l'écarte, même quand tous les autres noms correspondent
Un nom peut être faux de trois façons faciles à manquer. La première, c'est
JavaScript qui rencontre SQL : votre application écrit userId et la fonction
déclare user_id.
La deuxième est un préfixe. Certaines fonctions nomment leurs arguments
p_user_id, pour qu'on ne les confonde pas avec une colonne appelée user_id, et
l'appel doit alors porter le p_ lui aussi. Dans une
discussion chez Supabase,
l'appel envoyait id, nombre et trois autres, la fonction déclarait p_id,
p_nombre et le reste, et l'indice affichait chacun des bons noms.
La troisième est la règle qui renomme aussi les colonnes. Un nom tapé en SQL sans
guillemets doubles est ramené en minuscules, donc
create function get_orders(userId uuid) enregistre l'argument sous le nom
userid. Un
utilisateur de FlutterFlow
est tombé exactement là-dessus : l'appel envoyait userId, et l'indice répondait
(userid). La version colonne de cette erreur
a un tableau de ce que crée chaque graphie.
Pour voir les noms que la base a enregistrés, exécutez ceci dans le SQL Editor :
select p.proname, pg_get_function_arguments(p.oid)
from pg_proc p
join pg_namespace n on n.oid = p.pronamespace
where n.nspname = 'public' and p.proname = 'get_orders';
pg_get_function_arguments affiche les arguments tels qu'ils ont été déclarés,
avec leurs valeurs par défaut, ce qui montre aussi lesquels vous pouvez omettre.
La correction la plus sûre se fait dans l'application, parce qu'elle ne change
rien dans la base. Demandez à votre builder d'appeler la fonction avec ses noms
enregistrés : "get_orders prend user_id ; passez { user_id: … } dans chaque
appel .rpc() vers elle". Renommer l'argument est plus difficile qu'il n'y
paraît. La
documentation de Postgres
dit de CREATE OR REPLACE FUNCTION : "You cannot change the name already assigned
to any input parameter". Il faut supprimer la fonction et la recréer, et chaque
autre écran qui l'appelle sous l'ancien nom échoue alors de la même façon.
Cause 2 : la valeur était undefined, donc le nom n'est jamais parti
Un argument dont la valeur est undefined n'arrive jamais à PostgREST, et la
fonction est alors cherchée sans lui.
supabase-js envoie vos arguments en JSON, et JSON n'a pas de undefined. La
référence MDN de JSON.stringify
dit que ces valeurs "are either omitted (when found in an object) or changed to
null (when found in an array)". Cet appel, fait avant que l'utilisateur connecté
soit chargé :
await supabase.rpc('get_orders', { user_id: user?.id })
envoie donc {}, et la réponse est
Could not find the function public.get_orders without parameters in the schema cache.
Avec deux arguments dont l'un est undefined, les parenthèses ne listent que celui
qui est arrivé.
Le nom dans votre code est juste, et c'est pourquoi lire le code ne trouve rien. Le message, lui, le montre : les parenthèses sont vides, ou il leur manque un nom par rapport à ce que le code passe.
La correction consiste à faire l'appel une fois la valeur disponible. Quand la
fonction est écrite pour gérer une valeur absente, passez null exprès, que JSON
conserve.
Un filtre fait l'inverse avec la même valeur. .eq('user_id', user?.id) la place
dans la requête sous la forme du mot undefined, et une colonne uuid répond
invalid input syntax for type uuid.
Cause 3 : la fonction est dans un autre schéma
supabase.rpc() cherche dans le schéma public, celui que nomme le message, sauf
si vous lui dites autre chose. Une fonction créée ailleurs ne figure pas du tout
sur la liste de PostgREST :
il ne charge les fonctions
que depuis les schémas que votre projet expose par son API.
Cela se présente sous deux formes :
- la fonction a été créée dans un schéma à elle, comme
privateoubilling, et elle est appelée avec un simple.rpc('get_orders') - le schéma est écrit dans le nom, sous la forme
.rpc('billing.get_orders'). PostgREST lit toute la chaîne comme un seul nom et le cherche danspublic, donc le message ditpublic.billing.get_orders
Une fonction d'un autre schéma s'appelle avec
.schema('billing').rpc('get_orders', …), et ce schéma doit figurer sous Exposed
schemas dans les paramètres d'API du projet, comme le montre
le guide de Supabase sur les schémas personnalisés.
Tant que ce n'est pas le cas, la réponse devient PGRST106,
Invalid schema: billing, avec un indice qui liste les schémas exposés.
Exposer un schéma comme le fait ce guide ouvre chaque table qu'il contient. Le
guide donne à anon et à authenticated l'accès à chaque table du nouveau
schéma, et dès lors seules vos règles de
Row Level Security décident de ce
qu'un visiteur peut y lire.
La version table de cette erreur donne
la requête qui liste les tables d'un schéma où ces règles sont désactivées, à
lancer avant de l'exposer. Certaines fonctions sont rangées dans un schéma privé
pour que personne ne puisse les appeler de l'extérieur : notre
guide sur la récursion infinie dans une policy
en place une là précisément pour cette raison. Un appel à une telle fonction depuis
le navigateur reçoit PGRST202 à dessein, et son schéma doit rester non exposé.
Cause 4 : le nom de la fonction elle-même, ou aucune fonction
PostgREST cherche le nom exactement, lettre pour lettre, majuscules comprises.
- une faute de frappe, ou
getOrdersdans l'appel face àget_ordersdans la base - une fonction créée sous le nom
getOrderssans guillemets doubles, enregistrée commegetorderspar la même règle que ses arguments - une procédure. PostgREST ne liste que des fonctions, donc
create procedurecrée quelque chose que.rpc()ne peut pas atteindre, et il en va de même d'une fonction quireturns trigger, exécutée par un trigger et jamais par votre application
L'indice aide ici aussi. Quand aucune fonction de ce nom n'existe, PostgREST suggère le nom le plus proche qu'il connaît, s'il y en a un d'assez proche.
Ou bien la fonction n'a jamais été créée dans la base que votre application appelle. Si vous construisez avec Lovable, remontez le chat à la recherche d'un SQL qu'on vous a demandé d'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 n'avez pas approuvé, la fonction n'existe que dans le code qui l'appelle. Si quelqu'un l'a créée à la main, vérifiez qu'elle est allée dans le projet auquel votre application parle : une branche est un projet à part, avec sa propre base.
Cause 5 : le cache est vraiment périmé
Sur Supabase, c'est le cas rare. Chaque base Supabase a un event trigger,
pgrst_ddl_watch, qui envoie NOTIFY pgrst, 'reload schema' après chaque
CREATE FUNCTION et ALTER FUNCTION, et un second, pgrst_drop_watch, l'envoie
après la suppression d'une fonction. Les deux figurent dans
la mise en place de la base par Supabase.
Quand ce message n'arrive pas, rechargez la liste à la main dans le SQL Editor :
NOTIFY pgrst, 'reload schema';
Si rien ne change, la version colonne de cette erreur couvre les deux étapes suivantes, la file de notifications bloquée et le redémarrage du projet. Les deux marchent de la même façon pour les fonctions.
Quand deux fonctions partagent un nom
PostgREST ne choisit pas au hasard entre elles. Quand deux fonctions ont le même
nom et acceptent toutes deux les arguments envoyés par votre application, l'appel
échoue avec PGRST203 et HTTP 300 :
Could not choose the best candidate function between: public.get_orders(user_id => uuid), public.get_orders(user_id => text)
Corriger un PGRST202 est une façon d'en arriver là. Votre builder change le type
d'un argument avec CREATE OR REPLACE FUNCTION, et Postgres ne remplace rien. Sa
documentation
dit que les types d'arguments ne peuvent pas être changés ainsi : "if you tried,
you would actually be creating a new, distinct function". Les deux versions
existent désormais côte à côte.
L'indice de PostgREST pour ce cas dit "Try renaming the parameters or the function itself in the database so function overloading can be resolved". La correction la plus simple est de supprimer la version dont vous ne voulez pas, en nommant le type de son argument pour que Postgres sache de laquelle il s'agit :
drop function public.get_orders(text);
Vérifiez quelle version votre application appelle avant de supprimer l'une ou l'autre.
Appeler correctement une fonction Supabase
Passez un objet dont les clés sont les noms d'arguments de la fonction, écrits
comme la base les a enregistrés. Dans
le guide de Supabase sur les fonctions de base de données,
une fonction déclarée add_planet(name text) s'appelle avec
supabase.rpc('add_planet', { name: 'Jakku' }).
Dès que votre application peut appeler la fonction, n'importe qui d'autre le peut
aussi. Le même guide le dit clairement : "By default, any role can run a database
function." Cela inclut anon, le rôle derrière chaque requête d'un visiteur non
connecté. Une fonction que votre application appelle depuis le navigateur peut être
appelée par quiconque possède votre clé publique, avec les arguments de son choix.
Pour une fonction que seuls les utilisateurs connectés doivent exécuter, suivez le
guide : retirez execute à public et à anon, et rendez-le à authenticated.
revoke execute on function public.get_orders from public, anon;
grant execute on function public.get_orders to authenticated;
Vos tables sont l'autre moitié de ce que cette clé publique atteint. Notre scan gratuit vérifie depuis l'extérieur si elles livrent des lignes à quiconque la détient, et il ne demande aucun compte.
Modifier une fonction dont votre application dépend
Gardez une copie de la base d'avant la modification, et soyez prévenu quand quelque chose que votre application expose change.
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 copie d'avant votre modification contient vos fonctions telles qu'elles étaient définies alors, à côté de vos tables et de vos lignes
- 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
- 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 le message : les noms entre parenthèses sont ce que votre application a envoyé, et l'indice nomme ce que la base possède.
- Comparez les noms d'arguments lettre pour lettre, préfixe
p_compris. Un nom tapé en SQL sans guillemets est enregistré en minuscules. - Si les parenthèses sont vides ou qu'il manque un nom, cherchez une valeur restée
undefinedau moment de l'appel. - Vérifiez le schéma dans le message. Une fonction d'un autre schéma demande
.schema('nom').rpc(…)et un schéma exposé, et exposer un schéma rend aussi ses tables accessibles. - Si deux fonctions partagent le nom, supprimez la version que votre application n'appelle pas.
- N'exécutez
NOTIFY pgrst, 'reload schema';qu'une fois les noms en accord. - Retirez
executeàanonsur toute fonction qu'un visiteur non connecté ne doit jamais exécuter.
Commencez par les parenthèses, parce qu'elles contiennent exactement ce que votre application a envoyé. Avant de supprimer ou de remplacer une fonction dont votre application dépend, gardez une copie de la base d'avant la modification.
FAQ
Que signifie PGRST202 ?
PGRST202 est le code que PostgREST, la partie de Supabase qui répond aux appels supabase.rpc(), renvoie quand aucune fonction ne correspond à un appel. Il arrive avec HTTP 404 et le message "Could not find the function public.name(arguments) in the schema cache". Les noms entre parenthèses sont les arguments que votre application a envoyés, et public est le schéma où la recherche a eu lieu.
La fonction existe. Pourquoi mon appel RPC dit-il qu'elle manque ?
PostgREST reconnaît une fonction à son nom et à ses noms d'arguments pris ensemble. Envoyez chaque argument qui n'a pas de valeur par défaut, sous le nom exact que la base a enregistré, et rien que la fonction ne déclare pas. Un nom écrit en SQL sans guillemets doubles est enregistré en minuscules, donc userId dans un create function devient userid.
Pourquoi le message dit-il "without parameters" ?
Votre application n'a envoyé aucun argument. Avec supabase-js, la raison habituelle est une valeur restée undefined au moment de l'appel : les arguments voyagent en JSON, qui laisse de côté les valeurs undefined, donc { user_id: undefined } arrive sous la forme {}. Faites l'appel une fois la valeur disponible, ou passez null si la fonction est écrite pour gérer une valeur absente.
La fonction doit-elle être dans le schéma public ?
supabase.rpc() cherche dans public, sauf si vous choisissez un autre schéma avec .schema('nom'), et ce schéma doit figurer sous Exposed schemas dans les paramètres d'API du projet. Exposer un schéma rend son contenu accessible par l'API, alors mieux vaut le décider en connaissance de cause.
Comment recharger le cache de schéma de Supabase ?
Exécutez NOTIFY pgrst, 'reload schema'; dans le SQL Editor. Supabase envoie déjà ce message tout seul dès qu'une fonction est créée, modifiée ou supprimée, donc un rechargement n'aide que si le message n'est pas arrivé. Vérifiez d'abord les noms.