Files
supabase/apps/docs/content/guides/monitoring-and-debugging/debugging.mdx
T
0bbd64743c docs: move inspect and advisors into observability (#49503)
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## Stack

Draft stack extracted from `docs/monitoring`. Merge bottom-up.
Troubleshooting / debugging-guide rewrite is out of scope.

1. **#49503** move inspect and advisors ← **this PR**
2. #49501 split Studio logs from ClickHouse queries
3. #49500 treat reports as signal dashboards
4. #49502 add Observe the data hub
5. #49506 add agent setup components
6. #49504 add hire-an-agent templates
7. #49505 restructure observability nav and overview

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Docs update. First layer in the observability stack.

## What is the current behavior?

Inspect and advisors live under Database (`/guides/database/inspect`,
`/guides/database/database-advisors`). Observability readers have to
leave the monitoring section to find them.

## What is the new behavior?

- Moves inspect into `/guides/monitoring-and-debugging/inspect`
- Adds `/guides/monitoring-and-debugging/advisors` (replaces the
Database Advisors page)
- Adds redirects and updates Studio/docs links so old URLs keep working
- Adds both pages to the existing Monitoring nav so they are
discoverable before the later IA PR

## Additional context

Inspect and advisors pages render as standard MDX. Redirects cover
`/docs/guides/database/inspect`,
`/docs/guides/database/database-advisors`, and
`/docs/guides/database/database-linter`. Debugging-guide content is
unchanged except the inspect URL.

## Self-review

- No leftover `/guides/database/inspect` or
`/guides/database/database-advisors` links in docs guides or Studio
linter/AI surfaces (historical blog posts left as-is)
- Smoke test path updated to
`/docs/guides/monitoring-and-debugging/advisors`
<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a
href="https://cursor.com/agents/bc-a3cb5ece-925b-4046-b58a-5d69e9a9d794?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-a3cb5ece-925b-4046-b58a-5d69e9a9d794&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added a centralized Advisors guide for security and performance
checks.
- Updated database inspection guidance with live Postgres statistics,
cache hit-rate context, and query-analysis resources.

- **Documentation**
- Reorganized Advisors and database inspection content under Monitoring
and Debugging.
- Updated navigation, cross-references, in-product help links, and CLI
documentation links.
- Added permanent redirects from previous documentation URLs to preserve
access.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Saxon Fletcher <SaxonF@users.noreply.github.com>
Co-authored-by: Nik Richers <nik@validmind.ai>
2026-09-04 13:38:36 +10:00

99 lines
19 KiB
Plaintext

---
id: 'debugging'
title: 'Debugging guide'
description: 'Isolate and fix Supabase issues by reading the error, isolating the failing layer, and gathering evidence from logs.'
---
Debug by evidence, not by guessing. A Supabase error almost always surfaces at one layer but originates at another, so the fastest path to a fix is finding _where_ the problem is, not pattern-matching the symptom. Retrying a failed request rarely helps; isolating the layer does.
## Debug with AI tools
An AI agent can work through this loop for you, but only if it can read your project's evidence instead of guessing from the error message.
Debugging with an agent needs two things:
- The [Supabase MCP server](/docs/guides/ai-tools/mcp) provides the tools this guide relies on: `get_logs` for a per-service log dump, `query_logs` to run read-only SQL against your logs for filtering and aggregation (see [Querying with the Logs Explorer](/docs/guides/monitoring-and-debugging/logs#querying-with-the-logs-explorer) for the ClickHouse SQL syntax it accepts), `get_advisors` for security and performance findings, and `execute_sql` to inspect your schema and policies.
- The [Supabase agent skill](/docs/guides/ai-tools/ai-skills) teaches the agent this workflow: locate the failing layer, gather evidence from the matching log source, and verify the fix by re-running the operation that failed.
Install both in one step with the [Supabase plugin for AI coding agents](/docs/guides/ai-tools/plugins). Connecting an agent to your project carries security risks, so read the [MCP security best practices](/docs/guides/ai-tools/mcp#security-risks) first.
## Follow these debugging steps
Work through these steps in order, skipping straight to a fix before you have evidence for the cause is the most common way to waste time on a bug.
1. **Reproduce the issue and read the error precisely.** Capture the exact status code, the error code, and the full message, not a paraphrase. A `401` is not a `403`; `PGRST002` is not `PGRST106`; a Postgres `SQLSTATE` such as `42501`, `42P01`, or `23505` points at the exact failure. The precise error is your strongest clue. If you're using `supabase-js`, remember that errors are **returned, not thrown**, check the `error` field in the `{ data, error }` response object. Make sure your code inspects `error` — a swallowed error is why many bugs look like "nothing happened".
2. **Locate the failing layer.** Use the request stack below. The status code and error code usually name the layer for you.
3. **Gather evidence for that layer.** Query its logs, run the security and performance advisors, and inspect the schema. Logs are the primary tool, and the layer you identified in the previous step tells you which log source to query. See [Read the logs](#read-the-logs) below.
4. **Isolate the cause** using the troubleshooting guide for that layer (see [Find the guide for your symptom](#find-the-guide-for-your-symptom) below). Confirm your hypothesis against the evidence before you act. Most Supabase issues trace back to a small, known set of causes, and the guide explains how to tell them apart.
5. **Apply the fix, then verify.** Re-run the exact operation that failed and confirm it now succeeds, and that the corresponding log line is clean. A fix you haven't re-run is still a guess. If a couple of attempts don't resolve it, stop and gather more evidence rather than repeating the same change.
## Check the request stack
A request from a client passes through several layers before it reaches your data. Errors propagate upward, so the layer that _reports_ an error is often not the layer that _caused_ it.
Knowing the shape of the stack is what makes isolating the layer possible.
```
Client (supabase-js / SSR)
→ Edge / API gateway → edge_logs (HTTP status, routing, rate limits)
The gateway routes each request to ONE of these services. They run in parallel,
not as a chain:
├→ PostgREST (Data API) → postgrest_logs (low-signal; PGRST* evidence lives in edge_logs and postgres_logs)
├→ GoTrue (Auth) → auth_logs (login, JWT, OAuth, email)
├→ Storage API → storage_logs (uploads, object access)
└→ Realtime → realtime_logs (channels, presence, broadcast)
PostgREST, GoTrue, and Storage each reach the database independently:
→ Supavisor (connection pooler) → supavisor_logs (pooling, timeouts)
→ Postgres (SQL, RLS, triggers) → postgres_logs (SQLSTATE, RLS, functions)
```
Edge Functions sit outside this stack and log separately: `function_edge_logs` for the HTTP request to the function, and `function_logs` for `console` output from inside it.
<Admonition type="note">
A permission error or an unexpectedly empty result at the API layer is often a Postgres row-level security or privilege problem one layer down, though filters, authentication, query shape, or a stale schema cache can produce the same symptom. When in doubt, trace toward the database.
</Admonition>
## Read the logs
Once you know the layer, query that layer's log source directly rather than scanning everything. Pick one `source`, bound the time window, and select only the fields you need.
When a query comes up empty, widen along an anchor, such as a timestamp, request ID, or error code, to follow the same request into the adjacent source (for example from `edge_logs` into `postgres_logs`) instead of broadening into an unfiltered scan.
A wide, unfiltered query across every source buries the one line you need and, on paid projects, costs more in scanned data.
The [Logging guide](/docs/guides/monitoring-and-debugging/logs) covers the Logs Explorer, the available log sources, and how to write queries against them.
## Find the guide for your symptom
Match your symptom to a layer, confirm it against that layer's logs, then open the troubleshooting guide for the specific cause and fix. If a symptom could fit two layers (for example, an auth call failing with what looks like an RLS error), start with the layer closest to the database.
Supabase updates these troubleshooting guides continuously, so treat this table as a starting point rather than the final word: if your exact symptom isn't listed, search the [troubleshooting index](/docs/guides/troubleshooting) for the error string.
| Symptom / error | Layer → log source | Troubleshooting guides |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Empty `data` array with rows present; wrong rows returned; UPDATE/DELETE affects 0 rows; `42501` permission denied; `service_role` still blocked; policy not matching | RLS & access → `postgres_logs` | [Empty select array](/docs/guides/troubleshooting/why-is-my-select-returning-an-empty-data-array-and-i-have-data-in-the-table-xvOPgx) · [service_role hits RLS](/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z) · [Database API 42501](/docs/guides/troubleshooting/database-api-42501-errors) · [RLS Simplified](/docs/guides/troubleshooting/rls-simplified-BJTcS8) · [Deprecated RLS features](/docs/guides/troubleshooting/deprecated-rls-features-Pm77Zs) |
| `PGRST002`/`PGRST106`; "schema cache"; "could not find table/relationship"; new column or table not recognized; `42P01`; `520`; API returns nothing | Data API (PostgREST) → `edge_logs`, `postgres_logs` | [Refresh schema cache](/docs/guides/troubleshooting/refresh-postgrest-schema) · [PGRST002](/docs/guides/troubleshooting/postgrest-error-pgrst002-could-not-query-the-database-for-the-schema-cache-c396e9) · [New objects not recognized](/docs/guides/troubleshooting/postgrest-not-recognizing-new-columns-or-functions-bd75f5) · [42P01](/docs/guides/troubleshooting/resolving-42p01-relation-does-not-exist-error-W4_9-V) · [520 errors](/docs/guides/troubleshooting/fixing-520-errors-in-the-database-rest-api-Ur5-B2) · [API not returning](/docs/guides/troubleshooting/why-is-my-supabase-api-call-not-returning-PGzXw0) |
| Sign-in/sign-out/session broken; JWT "invalid claim"/"missing sub"; cookies not sent; OAuth redirect wrong; OTP/magic-link expired; MFA/TOTP fails; auth `500`/`503`; emails not arriving | Auth → `auth_logs`, `postgres_logs` | [401 missing sub](/docs/guides/troubleshooting/auth-error-401-invalid-claim-missing-sub--AFwMR) · [500 auth errors](/docs/guides/troubleshooting/resolving-500-status-authentication-errors-7bU5U8) · [503 AuthRetryableFetchError](/docs/guides/troubleshooting/auth-error-503-authretryablefetcherror-51b88c) · [OTP expired](/docs/guides/troubleshooting/otp-verification-failures-token-has-expired-or-otp_expired-errors-5ee4d0) · [OAuth not redirecting](/docs/guides/troubleshooting/oauth-sign-in-isnt-redirecting-on-the-server-side-ShGMtr) · [No auth emails](/docs/guides/troubleshooting/not-receiving-auth-emails-from-the-supabase-project-OFSNzw) · [Next.js auth](/docs/guides/troubleshooting/how-do-you-troubleshoot-nextjs---supabase-auth-issues-riMCZV) |
| `statement timeout`; duplicate key or sequence error; trigger errors; slow `ALTER`; blocked queries; disk/memory/swap pressure; index size | Database (Postgres) → `postgres_logs` | [Statement timeout](/docs/guides/troubleshooting/canceling-statement-due-to-statement-timeout-581wFv) · [Duplicate key / sequence](/docs/guides/troubleshooting/inserting-into-sequenceserial-table-causes-duplicate-key-violates-unique-constraint-error-pi6DnC) · [Blocked queries](/docs/guides/troubleshooting/how-to-check-if-my-queries-are-being-blocked-by-other-queries-NSKtR1) · [Disk not shrinking](/docs/guides/troubleshooting/disk-size-not-shrinking-after-deleting-data-135390) · [Autovacuum stalled](/docs/guides/troubleshooting/autovacuum-stalled-due-to-inactive-replication-slot-d55aa2) · [High CPU](/docs/guides/troubleshooting/high-cpu-usage) |
| "too many connections"; "remaining connection slots"; `CONNECT_TIMEOUT`; pooler vs. direct connection; read-only transaction; `prepared statement already exists`; `no pg_hba.conf entry`; IPv4/IPv6; SASL/SCRAM | Connections & pooler → `supavisor_logs`, `postgres_logs` | [Too many connections](/docs/guides/troubleshooting/too-many-connections-for-database-postgres) · [Remaining slots](/docs/guides/troubleshooting/database-error-remaining-connection-slots-are-reserved-for-non-replication-superuser-connections-3V3nIb) · [Prepared statement exists](/docs/guides/troubleshooting/error-prepared-statement-xxx-already-exists-3laqeM) · [Read-only transaction](/docs/guides/troubleshooting/resolving-cannot-execute-update-in-a-read-only-transaction-on-transaction-pooler-connections-ef582c) · [CONNECT_TIMEOUT](/docs/guides/troubleshooting/troubleshooting-connect_timeout-or-hanging-queries-in-vercel-serverless-functions-775f92) · [Supavisor terminology](/docs/guides/troubleshooting/supavisor-and-connection-terminology-explained-9pr_ZO) |
| Edge Function `401`/`404`/`500`/`503`/`504`/`546`; CPU/memory/wall-clock limit hit; won't deploy; boot error; WebSocket drop; `esm.sh` import fails | Edge Functions → `function_edge_logs`, `function_logs` | [401](/docs/guides/troubleshooting/edge-function-401-error-response) · [500](/docs/guides/troubleshooting/edge-function-500-error-response) · [503 boot](/docs/guides/troubleshooting/edge-function-503-response) · [504](/docs/guides/troubleshooting/edge-function-504-error-response) · [546 resource limit](/docs/guides/troubleshooting/edge-function-546-error-response) · [Shutdown reasons](/docs/guides/troubleshooting/edge-function-shutdown-reasons-explained) · [Deploy fails](/docs/guides/troubleshooting/edge-function-fails-deploy) · [esm.sh import](/docs/guides/troubleshooting/importing-stripe-or-other-modules-from-esmsh-on-deno-edge-functions-throws-an-error-TmbB5p) |
| Realtime `TIMED_OUT`; `TooManyChannels`; silent disconnect; missed database changes; broadcast-from-DB warning; heartbeats | Realtime → `realtime_logs` | [TIMED_OUT](/docs/guides/troubleshooting/realtime-connections-timed_out-status) · [TooManyChannels](/docs/guides/troubleshooting/realtime-too-many-channels-error) · [Silent disconnects](/docs/guides/troubleshooting/realtime-handling-silent-disconnections-in-backgrounded-applications-592794) · [Broadcast warning](/docs/guides/troubleshooting/realtime-warn-sending-broadcast-message) · [Heartbeats](/docs/guides/troubleshooting/realtime-heartbeat-messages) · [Logger](/docs/guides/troubleshooting/realtime-debugging-with-logger) |
| Upload or list fails; public bucket inaccessible; `relation "objects" does not exist`; file size limit; folder or RLS issue | Storage → `storage_logs`, `postgres_logs` | [Public bucket upload/list](/docs/guides/troubleshooting/why-cant-i-uploadlistetc-my-public-bucket-Z6CmGt) · [403 RLS on upload](/docs/guides/troubleshooting/storage-error-403-forbidden-new-row-violates-row-level-security-policy-on-upload-a94384) · [relation objects does not exist](/docs/guides/troubleshooting/relation-objects-does-not-exist-error-during-storage-uploads-8f21f0) · [File size limits](/docs/guides/troubleshooting/upload-file-size-restrictions-Y4wQLT) · [Folder ops / hierarchical RLS](/docs/guides/troubleshooting/supabase-storage-inefficient-folder-operations-and-hierarchical-rls-challenges-b05a4d) |
| Webhook not firing; `pg_cron` job not running; `pg_net` queue stuck; `42501 ... http_request_queue` | Database jobs → `postgres_logs` | [Webhook debugging](/docs/guides/troubleshooting/webhook-debugging-guide-M8sk47) · [pg_cron debugging](/docs/guides/troubleshooting/pgcron-debugging-guide-n1KTaz) · [42501 http_request_queue](/docs/guides/troubleshooting/42501--permission-denied-for-table-httprequestqueue-KnozmQ) |
| Reading or querying logs; interpreting Postgres logs; finding API errors in logs; reading metrics | Diagnostics → any log source | [Logging guide](/docs/guides/monitoring-and-debugging/logs) · [Interpret Postgres logs](/docs/guides/troubleshooting/how-to-interpret-and-explore-the-postgres-logs-OuCIOj) · [API errors in logs](/docs/guides/troubleshooting/discovering-and-interpreting-api-errors-in-the-logs-7xREI9) · [Logging levels](/docs/guides/troubleshooting/understanding-postgresql-logging-levels-and-how-they-impact-your-project-KXiJRm) · [View database metrics](/docs/guides/troubleshooting/how-to-view-database-metrics-uqf2z_) |
For query performance and schema-design questions such as indexing, `EXPLAIN`, N+1 queries, or partitioning, see the [Postgres guides](/docs/guides/database/overview).
Debugging is complete only once you've re-run the failing operation, confirmed it succeeds, and checked that the layer's logs show a clean result.
## Per-product debugging
Each Supabase product has its own debugging resources. Use these as a starting point when the error originates in a specific service.
- [Database — Inspect the database](/docs/guides/monitoring-and-debugging/inspect)
- [Auth — Error codes](/docs/guides/auth/debugging/error-codes)
- [Storage — Debugging](/docs/guides/storage/debugging/logs)
- [Edge Functions — Local debugging](/docs/guides/functions/debugging-tools)