## 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.

```text
pgrst303
```

## Use 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

1. Capture the full response, not just the code. PGRST303 wraps an HTTP 303, so find where it redirects to:

```bash
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.

2. 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:

```text
Check: the Location header target tells you whether auth or routing caused it
```
Expected output: you know whether to fix auth (login page) or routing (wrong path).

3. For RPC calls that should return data, add the Prefer header so PostgREST returns the representation instead of redirecting:

```bash
-H "Prefer: return=representation"
```
Expected output: the function result comes back as JSON in the body instead of a 303.

4. If you own the Postgres function, check its return path. Functions using `RETURN` with a redirect-style response or plpgsql `RAISE` with redirect info cause this:

```sql
-- 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
