pgrst303
Explains PostgREST error code PGRST303 and how to fix the underlying request. Use when Supabase or PostgREST clients log PGRST303, when a stored procedure returns an unexpected redirect, or when a POST behaves like a GET redirect. Not for PGRST116 row-not-found errors, for JWT auth failures, or for RLS denials.
TL;DR
PGRST303 is PostgREST telling you the request triggered an HTTP 303 (See Other) redirect, which almost always means a stored procedure or edge path returned a redirect response your client didnt expect. Fix it by checking what the RPC or endpoint actually returns, and make sure POST requests that expect data back use the Prefer: return=representation header.
pgrst303Use this when
- Supabase client logs show error code PGRST303
- Calling a Postgres function via RPC redirects instead of returning rows
- A POST to a PostgREST endpoint comes back as a redirect
Not for this skill when
- The code is PGRST116 (thats zero rows returned, a different fix)
- Auth fails with JWT or 401 errors (thats the key or session)
- RLS policies block the row (thats a 403/policy problem)
Steps
- Capture the full response, not just the code. PGRST303 wraps an HTTP 303, so find where it redirects to:
curl -i -X POST "https://example.com.supabase.co/rest/v1/rpc/YOUR_FUNCTION" \
-H "apikey value YOUR_ANON_KEY" \
-H "your auth header \
-d '{}'Expected output: the response headers include a Location: line. That URL is what your function or proxy returned; the 303 itself is a symptom.
- If the Location points at a login or consent page, your request lost its auth on a redirect hop. Re-authenticate and retry with credentials included:
Check: the Location header target tells you whether auth or routing caused itExpected output: you know whether to fix auth (login page) or routing (wrong path).
- For RPC calls that should return data, add the Prefer header so PostgREST returns the representation instead of redirecting:
-H "Prefer: return=representation"Expected output: the function result comes back as JSON in the body instead of a 303.
- If you own the Postgres function, check its return path. Functions using
RETURNwith a redirect-style response or plpgsqlRAISEwith redirect info cause this:
-- make the function return a plain value or row set, not a redirect
SELECT * FROM your_function();Expected output: the function returns data directly when called in SQL. If it errors or redirects there too, the bug is in the function body.
Variant phrasings
supabase-js throws PGRST303 on insert
The insert worked but the client asked for no return representation; add .select() to the query chain, which sets the Prefer header for you.
PGRST303 behind a reverse proxy
The proxy is issuing the redirect (http to https, or path rewrite). Check proxy logs before blaming PostgREST.
Why it happens
PostgREST maps HTTP semantics onto Postgres. A 303 means "go look elsewhere," which in the PostgREST world usually escapes from a function that returned redirect content, a proxy in front of the API, or an auth layer bouncing the request to a login page. The client library surfaces the code but hides the Location header, so people chase the code instead of the redirect target.
Edge cases
- Some clients follow redirects automatically and then fail on the second hop with a confusing error; disable auto-follow while debugging.
- A 303 on a GET with query params often means a trailing-slash redirect from the proxy; normalize the base URL.
- If the Location is the same URL you called, you have a redirect loop in the proxy config.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_IWP9VpHRZM7GaDeUGpVh9Q
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.