Basi della sicurezza
Supabase PGRST202: "Could not find the function in the schema cache"
Supabase "Could not find the function in the schema cache" riporta i nomi degli argomenti inviati dalla tua app. Confrontali con la funzione.

In breve
- Supabase "Could not find the function in the schema cache" (PGRST202) significa che nessuna funzione ha quel nome e accetta esattamente i nomi degli argomenti inviati dalla tua app. I nomi tra parentesi nel messaggio sono quelli che ha inviato la tua app.
- Controlla prima i nomi degli argomenti: userId inviato a una funzione che dichiara user_id, un prefisso p_ mancante, o un valore rimasto undefined e quindi mai inviato.
- Supabase aggiorna da solo il suo elenco di funzioni ogni volta che se ne crea, modifica o elimina una, quindi controlla i nomi e lo schema prima di ricaricare qualsiasi cosa.
Il tuo builder ha scritto una funzione del database che carica gli ordini di un cliente, e la pagina che la chiama resta vuota. La console del browser mostra questo:
{
"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" significa che PostgREST
non ha nessuna funzione con quel nome che accetti esattamente gli argomenti inviati
dalla tua app. PostgREST è la parte di Supabase che risponde alle chiamate
supabase.rpc() della tua app, e tiene un proprio elenco di tutte le funzioni che
può chiamare, chiamato schema cache.
Ecco la parte che quasi tutte le risposte sbagliano: ti dicono di ricaricare lo
schema cache. Su Supabase quell'elenco si aggiorna da solo ogni volta che una
funzione viene creata o modificata. Il messaggio ti ha già detto che cosa non va.
userId, tra parentesi, è quello che ha inviato la tua app. user_id, nel
suggerimento, è quello che la funzione si aspetta.
Che cosa significa "Could not find the function in the schema cache"?
Che nessuna funzione nello schema in cui ha cercato PostgREST ha quel nome insieme a esattamente quei nomi di argomenti.
Pensa a ogni funzione del database come a un modulo stampato appeso dietro uno
sportello: il suo nome in alto e una casella etichettata per ogni argomento. Quando
la tua app chiama supabase.rpc('get_orders', { userId: id }), consegna una copia
compilata. PostgREST cerca sul muro un modulo con lo stesso nome e le stesse
etichette. Se nessuno le ha, la copia viene respinta allo sportello, e il messaggio
ti rilegge le etichette che hai compilato.
Quattro dettagli sono fissati nel codice di PostgREST:
- il codice è
PGRST202e lo stato HTTP 404, quello di una pagina che non esiste - le parentesi elencano i nomi degli argomenti che ha inviato la tua app. Quando
non ne ha inviato nessuno, al loro posto il messaggio dice
without parameters public.davanti al nome è lo schema in cui ha cercato PostgREST- il suggerimento, quando c'è, nomina la funzione più vicina che PostgREST conosce, con i nomi degli argomenti di quella funzione
Confronta le parentesi con il suggerimento prima di qualsiasi altra cosa.
Causa 1: i nomi degli argomenti non corrispondono
PostgREST sceglie una funzione dal suo nome e dai nomi dei suoi argomenti insieme, quindi una funzione chiamata con i nomi sbagliati è, per PostgREST, una funzione che non esiste.
Le regole, dalla ricerca nel planner di PostgREST:
- ogni argomento senza valore predefinito va inviato, con il suo nome esatto
- un argomento con un valore predefinito si può tralasciare
- un nome che la funzione non dichiara la esclude, anche quando tutti gli altri nomi corrispondono
Un nome può essere sbagliato in tre modi facili da non notare. Il primo è
JavaScript che incontra SQL: la tua app scrive userId e la funzione dichiara
user_id.
Il secondo è un prefisso. Alcune funzioni chiamano i loro argomenti p_user_id,
così non si confondono con una colonna chiamata user_id, e allora anche la
chiamata deve portare il p_. In una
discussione su Supabase la
chiamata inviava id, nombre e altri tre, la funzione dichiarava p_id,
p_nombre e il resto, e il suggerimento stampava tutti i nomi giusti.
Il terzo è la regola che rinomina anche le colonne. Un nome scritto in SQL senza
virgolette doppie viene portato in minuscolo, quindi
create function get_orders(userId uuid) salva l'argomento come userid. Un
utente di FlutterFlow
ci è finito proprio così: la chiamata inviava userId e il suggerimento
rispondeva (userid). La versione per le colonne di questo errore
ha una tabella di quello che crea ogni grafia.
Per vedere i nomi che il database ha salvato, esegui questo nel 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 stampa gli argomenti come sono stati dichiarati, con i
loro valori predefiniti, quindi mostra anche quali puoi tralasciare.
La correzione più sicura è nell'app, perché non cambia niente nel database. Chiedi
al tuo builder di chiamare la funzione con i nomi salvati: "get_orders prende
user_id; passa { user_id: … } in ogni chiamata .rpc() a questa funzione".
Rinominare l'argomento è più difficile di quanto sembri. La
documentazione di Postgres
dice di CREATE OR REPLACE FUNCTION: "You cannot change the name already assigned
to any input parameter". La funzione va eliminata e ricreata, e ogni altra
schermata che la chiama con il vecchio nome poi fallisce allo stesso modo.
Causa 2: il valore era undefined, quindi il nome non è mai partito
Un argomento il cui valore è undefined non arriva mai a PostgREST, e la funzione
viene cercata senza di esso.
supabase-js invia i tuoi argomenti come JSON, e JSON non ha undefined. Il
riferimento MDN su JSON.stringify
dice che questi valori "are either omitted (when found in an object) or changed to
null (when found in an array)". Quindi questa chiamata, fatta prima che l'utente
connesso sia caricato:
await supabase.rpc('get_orders', { user_id: user?.id })
invia {}, e la risposta è
Could not find the function public.get_orders without parameters in the schema cache.
Con due argomenti di cui uno undefined, le parentesi elencano solo quello che è
arrivato.
Il nome nel tuo codice è giusto, ed è per questo che leggere il codice non lo trova. Il messaggio sì: le parentesi sono vuote, oppure manca un nome rispetto a quello che passa il codice.
La correzione è fare la chiamata quando il valore c'è. Se la funzione è scritta per
gestire un valore mancante, passa null apposta, che JSON conserva.
Un filtro fa il contrario con lo stesso valore. .eq('user_id', user?.id) lo
mette nella richiesta come la parola undefined, e una colonna uuid risponde
invalid input syntax for type uuid.
Causa 3: la funzione è in un altro schema
supabase.rpc() cerca nello schema public, quello che nomina il messaggio, a
meno che tu non gli dica altro. Una funzione creata altrove non è proprio
nell'elenco di PostgREST:
carica le funzioni
solo dagli schemi che il tuo progetto espone tramite la sua API.
Si presenta in due forme:
- la funzione è stata creata in uno schema tutto suo, come
privateobilling, e viene chiamata con un semplice.rpc('get_orders') - lo schema è scritto nel nome, come
.rpc('billing.get_orders'). PostgREST legge l'intera stringa come un unico nome e lo cerca inpublic, quindi il messaggio dicepublic.billing.get_orders
Una funzione in un altro schema si chiama con
.schema('billing').rpc('get_orders', …), e quello schema deve comparire in
Exposed schemas nelle impostazioni API del progetto, come mostra
la guida di Supabase sugli schemi personalizzati.
Finché non c'è, la risposta diventa PGRST106, Invalid schema: billing, con un
suggerimento che elenca gli schemi esposti.
Esporre uno schema come fa quella guida apre ogni tabella che contiene. La guida dà
ad anon e ad authenticated l'accesso a ogni tabella del nuovo schema, e da quel
momento solo le tue regole di
Row Level Security decidono che cosa
può leggere lì un visitatore.
La versione per tabelle di questo errore
ha la query che elenca le tabelle di uno schema con quelle regole spente, da
eseguire prima di esporlo. Alcune funzioni stanno in uno schema privato proprio
perché nessuno possa chiamarle dall'esterno: la nostra
guida alla ricorsione infinita in una policy
ne mette una lì esattamente per questo. Una chiamata dal browser a una funzione
così riceve PGRST202 di proposito, e il suo schema deve restare non esposto.
Causa 4: il nome della funzione stessa, o nessuna funzione
PostgREST cerca il nome in modo esatto, lettera per lettera e con maiuscole e minuscole.
- un refuso, oppure
getOrdersnella chiamata controget_ordersnel database - una funzione creata come
getOrderssenza virgolette doppie, che viene salvata comegetordersper la stessa regola dei suoi argomenti - una procedura. PostgREST elenca solo funzioni, quindi
create procedurecrea qualcosa che.rpc()non può raggiungere, e lo stesso vale per una funzione chereturns trigger, che viene eseguita da un trigger e mai dalla tua app
Anche qui il suggerimento aiuta. Quando non esiste nessuna funzione con quel nome, PostgREST suggerisce il nome più vicino che ha, se uno è abbastanza simile.
Oppure la funzione non è mai stata creata nel database che la tua app chiama. Se costruisci con Lovable, ripercorri la chat cercando SQL che ti è stato chiesto di approvare. La documentazione Supabase di Lovable dice che "writes the SQL, shows it to you, and asks for your approval in the project chat before running it". Finché non approvi, la funzione esiste solo nel codice che la chiama. Se qualcuno l'ha creata a mano, controlla che sia finita nel progetto con cui parla la tua app: un branch è un progetto a parte con il suo database.
Causa 5: la cache è davvero vecchia
Su Supabase è il caso raro. Ogni database Supabase ha un event trigger,
pgrst_ddl_watch, che invia NOTIFY pgrst, 'reload schema' dopo ogni
CREATE FUNCTION e ALTER FUNCTION, e un secondo, pgrst_drop_watch, lo invia
dopo che una funzione è stata eliminata. Si trovano entrambi nella
configurazione del database di Supabase.
Quando quel messaggio non arriva, ricarica l'elenco a mano nel SQL Editor:
NOTIFY pgrst, 'reload schema';
Se non cambia niente, la versione per le colonne di questo errore copre i due passi successivi, la coda di notifiche bloccata e il riavvio del progetto. Valgono allo stesso modo per le funzioni.
Quando due funzioni condividono un nome
PostgREST non tira a indovinare tra le due. Quando due funzioni hanno lo stesso
nome ed entrambe accettano gli argomenti inviati dalla tua app, la chiamata
fallisce con PGRST203 e HTTP 300:
Could not choose the best candidate function between: public.get_orders(user_id => uuid), public.get_orders(user_id => text)
Correggere un PGRST202 è uno dei modi per arrivarci. Il tuo builder cambia il tipo
di un argomento con CREATE OR REPLACE FUNCTION, e Postgres non sostituisce
niente. La sua
documentazione
dice che i tipi degli argomenti non si possono cambiare così: "if you tried, you
would actually be creating a new, distinct function". Adesso esistono entrambe le
versioni, una accanto all'altra.
Il suggerimento di PostgREST per questo caso dice "Try renaming the parameters or the function itself in the database so function overloading can be resolved". La correzione più semplice è eliminare la versione che non vuoi, indicando il tipo del suo argomento perché Postgres sappia di quale si tratta:
drop function public.get_orders(text);
Controlla quale versione chiama la tua app prima di eliminarne una.
Chiamare nel modo giusto una funzione Supabase
Passa un oggetto le cui chiavi sono i nomi degli argomenti della funzione, scritti
come li ha salvati il database. Nella
guida di Supabase alle funzioni del database,
una funzione dichiarata come add_planet(name text) si chiama con
supabase.rpc('add_planet', { name: 'Jakku' }).
Appena la tua app può chiamare la funzione, può farlo anche chiunque altro. La
stessa guida lo dice chiaramente: "By default, any role can run a database
function." Questo include anon, il ruolo dietro ogni richiesta di un visitatore
che non ha fatto l'accesso. Una funzione che la tua app chiama dal browser può
chiamarla chiunque abbia la tua chiave pubblica, con gli argomenti che preferisce.
Per una funzione che devono eseguire solo gli utenti connessi, segui la guida:
togli execute a public e ad anon, e restituiscilo ad authenticated.
revoke execute on function public.get_orders from public, anon;
grant execute on function public.get_orders to authenticated;
Le tue tabelle sono l'altra metà di quello che raggiunge quella chiave pubblica. La nostra scansione gratuita controlla dall'esterno se consegnano righe a chiunque la possieda, e non chiede un account.
Modificare una funzione da cui dipende la tua app
Tieni una copia del database da prima della modifica, e vieni a saperlo quando cambia qualcosa che la tua app espone.
Reeve Care tiene una copia del tuo database Supabase:
- una copia cifrata secondo una pianificazione, sullo spazio di archiviazione di Reeve nell'UE, fuori dal tuo account Supabase
- la copia da prima della tua modifica contiene le tue funzioni come erano definite allora, accanto a tabelle e righe
- ogni copia verificata prima di contare, contando le righe di ogni tabella
- anche i file caricati, appena colleghi una credenziale Storage
- un ripristino con un clic, con una copia di sicurezza dello stato attuale presa prima
- tutto quello che fa Monitor
Reeve Monitor continua a controllare dall'esterno:
- se la tua app è raggiungibile, controllato ogni minuto
- il controllo di sicurezza completo ogni ora, su un massimo di tre app
- un messaggio quando un risultato cambia, così un deploy che cambia ciò che la tua app espone ti raggiunge senza che tu debba andare a guardare
- un report mensile, in linguaggio semplice, di quello che ha visto
Che cosa fare adesso
Cosa fare
- Leggi il messaggio: i nomi tra parentesi sono quelli che ha inviato la tua app, e il suggerimento nomina quello che ha il database.
- Confronta i nomi degli argomenti lettera per lettera, prefisso
p_compreso. Un nome scritto in SQL senza virgolette viene salvato in minuscolo. - Se le parentesi sono vuote o manca un nome, cerca un valore rimasto
undefinedal momento della chiamata. - Controlla lo schema nel messaggio. Una funzione in un altro schema richiede
.schema('nome').rpc(…)e uno schema esposto, ed esporne uno rende raggiungibili anche le sue tabelle. - Se due funzioni condividono il nome, elimina la versione che la tua app non chiama.
- Esegui
NOTIFY pgrst, 'reload schema';solo quando i nomi corrispondono. - Togli
executeadanonsu qualsiasi funzione che un visitatore non connesso non deve mai eseguire.
Parti dalle parentesi, perché contengono esattamente quello che ha inviato la tua app. Prima di eliminare o sostituire una funzione da cui dipende la tua app, tieni una copia del database da prima della modifica.
FAQ
Che cosa significa PGRST202?
PGRST202 è il codice che PostgREST, la parte di Supabase che risponde alle chiamate supabase.rpc(), restituisce quando nessuna funzione corrisponde a una chiamata. Arriva con HTTP 404 e il messaggio "Could not find the function public.name(arguments) in the schema cache". I nomi tra parentesi sono gli argomenti che ha inviato la tua app, e public è lo schema in cui ha cercato.
La funzione esiste. Perché la mia chiamata RPC dice che manca?
PostgREST riconosce una funzione dal suo nome e dai nomi dei suoi argomenti insieme. Invia ogni argomento senza valore predefinito, esattamente con il nome che il database ha salvato, e niente che la funzione non dichiari. Un nome scritto in SQL senza virgolette doppie viene salvato in minuscolo, quindi userId in un create function diventa userid.
Perché l'errore dice "without parameters"?
La tua app non ha inviato nessun argomento. Con supabase-js il motivo abituale è un valore rimasto undefined al momento della chiamata: gli argomenti viaggiano come JSON, che lascia fuori i valori undefined, quindi { user_id: undefined } arriva come {}. Fai la chiamata quando il valore c'è, oppure passa null se la funzione è scritta per gestire un valore mancante.
La funzione deve stare nello schema public?
supabase.rpc() cerca in public a meno che tu non scelga un altro schema con .schema('nome'), e quello schema deve comparire in Exposed schemas nelle impostazioni API del progetto. Esporre uno schema rende raggiungibile dall'API quello che contiene, quindi conviene deciderlo apposta.
Come ricarico lo schema cache di Supabase?
Esegui NOTIFY pgrst, 'reload schema'; nel SQL Editor. Supabase invia già quel messaggio da solo ogni volta che una funzione viene creata, modificata o eliminata, quindi ricaricare aiuta solo quando il messaggio non è arrivato. Controlla prima i nomi.