Supabase Edge Functions error tracking your coding agent can read

Supabase Edge Functions run on Deno, and when one throws, the caller sees a 500 and the details sit in the function logs. That is where the server code of a Lovable or Bolt app built on Supabase runs too. One shared file reports each error to Runheed with fetch (no package to install), and your coding agent reads the error, the request and the stack trace over MCP.

Set it up

  1. 1.In your project (Supabase dashboard: Edge Functions > Secrets, or the CLI) add the pk_... part of your project DSN as RUNHEED_KEY.

    terminalbash
    supabase secrets set RUNHEED_KEY=pk_...
  2. 2.Create one shared file. It sends the error to the HTTP ingest endpoint and never lets reporting break your function.

    supabase/functions/_shared/runheed.tstypescript
    const KEY = Deno.env.get('RUNHEED_KEY');
    const INGEST = 'https://runheed.com/api/ingest';
    
    function frames(stack = '') {
      return stack.split('\n').slice(1).flatMap((line) => {
        const m = line.match(/at (?:(.+?) \()?(\S+?):(\d+):(\d+)\)?$/);
        if (!m) return [];
        return [{ function: m[1] ?? '<anonymous>', filename: m[2], lineno: Number(m[3]), colno: Number(m[4]), inApp: !m[2].startsWith('ext:') && !m[2].includes('deno.land') }];
      });
    }
    
    export async function reportError(err: unknown, req?: Request, extra: Record<string, unknown> = {}) {
      if (!KEY) return;
      const e = err instanceof Error ? err : new Error(String(err));
      try {
        await fetch(INGEST, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json', 'X-Runheed-Key': KEY },
          body: JSON.stringify({
            errorType: e.name || 'Error',
            errorMessage: e.message || String(err),
            stacktrace: frames(e.stack),
            platform: 'deno',
            runtime: `deno ${Deno.version.deno}`,
            environment: Deno.env.get('RUNHEED_ENV') ?? 'production',
            request: req ? { method: req.method, url: req.url } : undefined,
            extra,
            timestamp: new Date().toISOString(),
          }),
        });
      } catch {
        // Reporting failed; the function still answers.
      }
    }
    
    export function withRunheed(handler: (req: Request) => Response | Promise<Response>) {
      return async (req: Request): Promise<Response> => {
        try {
          return await handler(req);
        } catch (err) {
          await reportError(err, req);
          return new Response(JSON.stringify({ error: 'Internal error' }), { status: 500, headers: { 'Content-Type': 'application/json' } });
        }
      };
    }
  3. 3.Wrap each function's handler. Errors you catch yourself can be sent with reportError(err, req, { anything: "useful" }).

    supabase/functions/checkout/index.tstypescript
    import { withRunheed } from '../_shared/runheed.ts';
    
    Deno.serve(withRunheed(async (req) => {
      const { cartId } = await req.json();
      // ...your code
      return Response.json({ ok: true, cartId });
    }));
  4. 4.Deploy the functions, then connect your agent with the server URL and a sign-in (Claude Code shown; Cursor, claude.ai and ChatGPT take the same URL).

    terminalbash
    supabase functions deploy
    claude mcp add --transport http runheed https://runheed.com/api/mcp

The npm and PyPI releases are not out yet, so these commands install the same package files straight from runheed.com. Nothing else changes when the registry versions ship.

What it catches

  • Any error thrown inside a wrapped Edge Function handler, with the method, URL and stack trace
  • Errors you report yourself with reportError, with whatever context you pass
  • The same errors from the server side of Lovable and Bolt apps that run on Supabase

What it does not do

  • Errors in the browser part of the app are not captured; there is no browser SDK yet
  • Errors raised inside Postgres (RLS policies, triggers, database functions) are only seen when a function receives them and throws or reports them
  • Errors your code catches and turns into a response are not sent unless you call reportError

Then ask your agent

> what broke in production since the last deploy? fix the top one and resolve it with the commit hash

Common Supabase Edge Functions errors

Plans from $29/moOther agents and editorsCancel any time from the billing portal