How to fix PGRST101: Missing Content-Type header in Supabase

SupabaseBEGINNERMEDIUMUpdated Dec 22, 2025· 111 views

Supabase (PostgREST) rejects any POST/PATCH/PUT request that transports a body without so much as a Content-Type header. The 405/PGRST101 response is PostgREST telling you it has no idea how to deserialize the payload, so the mutation never reaches the database. Setting the right media type fixes the error instantly.

Quick fix

Fixes PGRST101: Missing Content-Type header

curl -v -X POST https://your-project.supabase.co/rest/v1/widgets   -H "apikey: YOUR_ANON_KEY"   -H "Authorization: Bearer YOUR_JWT"   -H "Content-Type: application/json"   -d '{"name":"test"}'
  1. Confirm the header is missing
  2. Explicitly set Content-Type when you build the request
  3. Let the browser set the header for FormData or multipart payloads
  4. Verify edge proxies or functions forward headers
supabase — error
curl -v -X POST https://your-project.supabase.co/rest/v1/widgets -H "apikey: YOUR_ANON_KEY" -H "Authorization: Bearer YOUR_JWT" -H "Content-Type: application/json" -d '{"name":"test"}'
PGRST101: Missing Content-Type header

What this error means

PostgREST runs in front of every Supabase REST request and validates the HTTP verb, query string, headers, and body before it hits PostgreSQL. The "Missing Content-Type header" variant of PGRST101 surfaces when PostgREST sees a request body but cannot determine the media type because the request failed to send any `Content-Type` header. Without that header, PostgREST cannot choose a media type handler to parse JSON, URL-encoded, or multipart data, so it responds with HTTP 405 and rejects the operation as if you're calling an unsupported verb. The group-1 error table in the PostgREST docs shows that these validations live in the same guardrail as malformed queries and invalid headers, which is why PGRST101 is triggered before any SQL runs.

Typical symptoms

  • POST/PATCH/PUT requests to https://<project>.supabase.co/rest/v1/... return HTTP 405 with "PGRST101: Missing Content-Type header."
  • Supabase logs (or the client error object) show PGRST101 even though permissions and RLS look correct.
  • No rows are inserted/updated despite a JSON body being submitted.
  • Raw fetch/curl calls that omit headers work on GET but fail on write operations.
  • Requests proxied through edge middleware or API gateways suddenly start failing when those components strip or overwrite headers.

Common causes

  1. JSON, form-encoded, or multipart payloads sent without an explicit Content-Type header (curl defaults to application/x-www-form-urlencoded when you omit -H).
  2. Using fetch/axios/supabase.functions in environments where headers are overwritten or sniffed out (for example, frameworks calling setRequestHeader without preserving existing values).
  3. Edge rewrites, proxies, or middleware intentionally drop Content-Type to circumvent caching, leaving PostgREST blind.
  4. Manual requests built with FormData without letting the browser auto-set the `Content-Type` with the boundary.
  5. Third-party automation (bots, Zapier, etc.) hitting your Supabase REST endpoints without headers.

How to fix "PGRST101: Missing Content-Type header"

1Confirm the header is missing

Inspect the HTTP exchange with curl, a browser devtool, or a network proxy. The request must include the Content-Type that matches the payload.

bash
curl -v -X POST https://your-project.supabase.co/rest/v1/widgets   -H "apikey: YOUR_ANON_KEY"   -H "Authorization: Bearer YOUR_JWT"   -H "Content-Type: application/json"   -d '{"name":"test"}'

If the Content-Type line is absent, PostgREST raises PGRST101. Re-run curl with the header and you should get a 201/200 response instead of 405.

2Explicitly set Content-Type when you build the request

When you call Supabase via fetch, axios, or another HTTP client, always add the header before calling JSON.stringify on the payload.

javascript
const response = await fetch('https://your-project.supabase.co/rest/v1/widgets', {
  method: 'POST',
  headers: {
    apikey: process.env.SUPABASE_ANON_KEY,
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json', // required
  },
  body: JSON.stringify({ name: 'test' }),
});

If you build headers by merging objects, make sure you don’t accidentally remove Content-Type. Supabase?s JS client already does this for you when you call .insert(), but custom fetch wrappers still need the header.

3Let the browser set the header for FormData or multipart payloads

Browsers set the Content-Type (with the boundary) automatically when you pass a FormData instance. Do not manually override it with a string such as 'multipart/form-data', because that strips the boundary and can trigger the same error. Instead, only append Content-Type when you control the media type:

javascript
const form = new FormData();
form.append('file', fileInput.files[0]);

await fetch('https://your-project.supabase.co/rest/v1/uploads', {
  method: 'POST',
  headers: {
    apikey: SUPABASE_KEY,
    Authorization: `Bearer ${token}`,
    // DO NOT set Content-Type here when using FormData
  },
  body: form,
});

If you need to send JSON, make sure you call JSON.stringify and set Content-Type: application/json explicitly.

4Verify edge proxies or functions forward headers

If you front Supabase with Cloudflare, Vercel, or your own API gateway, confirm those services do not drop the Content-Type header. Inspect the raw request reaching Supabase or add temporary logging to the middleware:

javascript
addEventListener('fetch', (event) => {
  console.log('incoming headers', Object.fromEntries(event.request.headers));
  return event.respondWith(fetch(event.request));
});

If the header disappears before Supabase sees it, configure the edge layer to pass through all headers or rebuild the request and re-add Content-Type before forwarding.

5Use Supabase client helpers to avoid manual headers

The official Supabase libraries set the required Content-Type automatically when you use the table helpers or service functions. Replace raw fetch calls with:

javascript
await supabase.from('widgets').insert({ name: 'test' });

If you still need custom fetch logic (for example, fetching signed URLs or invoking edge functions), copy the headers that the Supabase client sends by default so that PostgREST receives the same metadata.

Advanced notes

PostgREST’s error catalog groups missing headers under “Group 1 – Api Request” because the proxy validates HTTP semantics before hitting SQL. The same table also lists PGRST107 for invalid Content-Type values, which means that once you add Content-Type: application/json or another valid MIME type, PostgREST happily routes the request to the JSON or form parser documented in the PostgREST API reference.

Frequently asked questions

What does "PGRST101: Missing Content-Type header" mean?
PostgREST runs in front of every Supabase REST request and validates the HTTP verb, query string, headers, and body before it hits PostgreSQL. The "Missing Content-Type header" variant of PGRST101 surfaces when PostgREST sees a request body but cannot determine the media type because the request failed to send any Content-Type header. Without that header, PostgREST cannot choose a media type handler to parse JSON, URL-encoded, or multipart data, so it responds with HTTP 405 and rejects the operation as if you're calling an unsupported verb.
How do I fix "PGRST101: Missing Content-Type header"?
Supabase (PostgREST) rejects any POST/PATCH/PUT request that transports a body without so much as a Content-Type header. The 405/PGRST101 response is PostgREST telling you it has no idea how to deserialize the payload, so the mutation never reaches the database. Setting the right media type fixes the error instantly.
What causes "PGRST101: Missing Content-Type header"?
JSON, form-encoded, or multipart payloads sent without an explicit Content-Type header (curl defaults to application/x-www-form-urlencoded when you omit -H). Using fetch/axios/supabase.functions in environments where headers are overwritten or sniffed out (for example, frameworks calling setRequestHeader without preserving existing values). Edge rewrites, proxies, or middleware intentionally drop Content-Type to circumvent caching, leaving PostgREST blind.
Is the "PGRST101: Missing Content-Type header" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading