Skip to content

Nil Pointer Dereference in timeoutMiddleware #2233

@redcapital

Description

@redcapital

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

Intermittent panic in middleware.go:392 when processing /verify requests. Sending this request:

POST /auth/v1/verify

{"token_hash":"550109c327f4b8484e537add17dcfaff8b0fb658377ef916d489fec7","type":"email"}

sometimes result in a response

{"code":500,"error_code":"unexpected_failure","msg":"Internal Server Error","error_id":"2f896104-...."}

and error logs contain

{
  "component": "api",
  "duration": 4728088,
  "level": "info",
  "method": "POST",
  "msg": "request completed",
  "panic": "runtime error: invalid memory address or nil pointer dereference",
  "path": "/verify",
  "referer": "https://...",
  "remote_addr": "...",
  "request_id": "...",
  "stack": "goroutine 59965787 [running]:\nruntime/debug.Stack()\n\t/usr/local/go/src/runtime/debug/stack.go:26 +0x5e\ngithub.com/supabase/auth/internal/api.recoverer.func1.1()\n\t/go/src/github.com/supabase/auth/internal/api/errors.go:49 +0x74\npanic({0x10f4300?, 0x1cc1a30?})\n\t/usr/local/go/src/runtime/panic.go:791 +0x132\ngithub.com/supabase/auth/internal/api.NewAPIWithVersion.timeoutMiddleware.func5.1({0x7f793aef0388, 0xc00071b600}, 0xc00025b7c0)\n\t/go/src/github.com/supabase/auth/internal/api/middleware.go:392 +0x376\nnet/http.HandlerFunc.ServeHTTP(0xc000e05050?, {0x7f793aef0388?, 0xc00071b600?}, 0x140?)\n\t/usr/local/go/src/net/http/server.go:2220 +0x29\ngithub.com/supabase/auth/internal/api.recoverer.func1({0x7f793aef0388?, 0xc00071b600?}, 0xc00001216b?)\n\t/go/src/github.com/supabase/auth/internal/api/errors.go:62 +0x6c\nnet/http.HandlerFunc.ServeHTTP(0xc00025b7c0?, {0x7f793aef0388?, 0xc00071b600?}, 0xdc346f?)\n\t/usr/local/go/src/net/http/server.go:2220 +0x29\ngithub.com/sebest/xff.(*XFF).Handler-fm.(*XFF).Handler.func1({0x7f793aef0388, 0xc00071b600}, 0xc00025b7c0)\n\t/go/pkg/mod/github.com/sebest/[email protected]/xff.go:128 +0x9e\nnet/http.HandlerFunc.ServeHTTP(0xc00025b680?, {0x7f793aef0388?, 0xc00071b600?}, 0x7f793afe6fa8?)\n\t/usr/local/go/src/net/http/server.go:2220 +0x29\ngithub.com/go-chi/chi/v5/middleware.RequestLogger.func1.1({0x146be00, 0xc0003fc2a0}, 0xc00025b680)\n\t/go/pkg/mod/github.com/go-chi/chi/[email protected]/middleware/logger.go:55 +0x154\nnet/http.HandlerFunc.ServeHTTP(0x1460be0?, {0x146be00?, 0xc0003fc2a0?}, 0x410805?)\n\t/usr/local/go/src/net/http/server.go:2220 +0x29\ngithub.com/supabase/auth/internal/api.NewAPIWithVersion.NewStructuredLogger.func3.1({0x146be00, 0xc0003fc2a0}, 0xc00025b680)\n\t/go/src/github.com/supabase/auth/internal/observability/request-logger.go:36 +0xfd\nnet/http.HandlerFunc.ServeHTTP(0xc00025b540?, {0x146be00?, 0xc0003fc2a0?}, 0x4732a403d5df5e84?)\n\t/usr/local/go/src/net/http/server.go:2220 +0x29\ngithub.com/supabase/auth/internal/api.NewAPIWithVersion.AddRequestID.func4.1({0x146be00, 0xc0003fc2a0}, 0xc00025b540)\n\t/go/src/github.com/supabase/auth/internal/observability/request-logger.go:24 +0xfb\nnet/http.HandlerFunc.ServeHTTP(0x14701b0?, {0x146be00?, 0xc0003fc2a0?}, 0x1cc2980?)\n\t/usr/local/go/src/net/http/server.go:2220 +0x29\ngithub.com/go-chi/chi/v5.(*Mux).ServeHTTP(0xc000263380, {0x146be00, 0xc0003fc2a0}, 0xc00025b400)\n\t/go/pkg/mod/github.com/go-chi/chi/[email protected]/mux.go:90 +0x2ee\ngithub.com/supabase/auth/internal/api.(*router).ServeHTTP(0xc0001520d0?, {0x146be00?, 0xc0003fc2a0?}, 0xc00025b400?)\n\t/go/src/github.com/supabase/auth/internal/api/router.go:55 +0x28\ngithub.com/supabase/auth/internal/api.NewAPIWithVersion.(*Cors).Handler.func9({0x146be00, 0xc0003fc2a0}, 0xc00025b400)\n\t/go/pkg/mod/github.com/rs/[email protected]/cors.go:289 +0x184\nnet/http.HandlerFunc.ServeHTTP(0xc000eb9b40?, {0x146be00?, 0xc0003fc2a0?}, 0x100c0005bc588?)\n\t/usr/local/go/src/net/http/server.go:2220 +0x29\ngithub.com/supabase/auth/internal/api.(*API).ServeHTTP(0xc00071b56c?, {0x146be00?, 0xc0003fc2a0?}, 0xc000eb9b88?)\n\t/go/src/github.com/supabase/auth/internal/api/api.go:331 +0x25\ngithub.com/supabase/auth/internal/reloader.(*AtomicHandler).ServeHTTP(0x410805?, {0x146be00?, 0xc0003fc2a0?}, 0xc0003fc201?)\n\t/go/src/github.com/supabase/auth/internal/reloader/handler.go:41 +0x71\nnet/http.serverHandler.ServeHTTP({0x1467ce0?}, {0x146be00?, 0xc0003fc2a0?}, 0x6?)\n\t/usr/local/go/src/net/http/server.go:3210 +0x8e\nnet/http.(*conn).serve(0xc000772090, {0x1470178, 0xc000600f30})\n\t/usr/local/go/src/net/http/server.go:2092 +0x5d0\ncreated by net/http.(*Server).Serve in goroutine 1\n\t/usr/local/go/src/net/http/server.go:3360 +0x485\n",
  "status": 500,
  "time": "2025-10-30T05:33:48Z"
}

stacktrace formatted for readability:

goroutine 59965787 [running]:
runtime/debug.Stack()
	/usr/local/go/src/runtime/debug/stack.go:26 +0x5e
github.com/supabase/auth/internal/api.recoverer.func1.1()
	/go/src/github.com/supabase/auth/internal/api/errors.go:49 +0x74
panic({0x10f4300?, 0x1cc1a30?})
	/usr/local/go/src/runtime/panic.go:791 +0x132
github.com/supabase/auth/internal/api.NewAPIWithVersion.timeoutMiddleware.func5.1({0x7f793aef0388, 0xc00071b600}, 0xc00025b7c0)
	/go/src/github.com/supabase/auth/internal/api/middleware.go:392 +0x376
net/http.HandlerFunc.ServeHTTP(0xc000e05050?, {0x7f793aef0388?, 0xc00071b600?}, 0x140?)
	/usr/local/go/src/net/http/server.go:2220 +0x29
github.com/supabase/auth/internal/api.recoverer.func1({0x7f793aef0388?, 0xc00071b600?}, 0xc00001216b?)
	/go/src/github.com/supabase/auth/internal/api/errors.go:62 +0x6c
net/http.HandlerFunc.ServeHTTP(0xc00025b7c0?, {0x7f793aef0388?, 0xc00071b600?}, 0xdc346f?)
	/usr/local/go/src/net/http/server.go:2220 +0x29
github.com/sebest/xff.(*XFF).Handler-fm.(*XFF).Handler.func1({0x7f793aef0388, 0xc00071b600}, 0xc00025b7c0)
	/go/pkg/mod/github.com/sebest/[email protected]/xff.go:128 +0x9e
net/http.HandlerFunc.ServeHTTP(0xc00025b680?, {0x7f793aef0388?, 0xc00071b600?}, 0x7f793afe6fa8?)
	/usr/local/go/src/net/http/server.go:2220 +0x29
github.com/go-chi/chi/v5/middleware.RequestLogger.func1.1({0x146be00, 0xc0003fc2a0}, 0xc00025b680)
	/go/pkg/mod/github.com/go-chi/chi/[email protected]/middleware/logger.go:55 +0x154
net/http.HandlerFunc.ServeHTTP(0x1460be0?, {0x146be00?, 0xc0003fc2a0?}, 0x410805?)
	/usr/local/go/src/net/http/server.go:2220 +0x29
github.com/supabase/auth/internal/api.NewAPIWithVersion.NewStructuredLogger.func3.1({0x146be00, 0xc0003fc2a0}, 0xc00025b680)
	/go/src/github.com/supabase/auth/internal/observability/request-logger.go:36 +0xfd
net/http.HandlerFunc.ServeHTTP(0xc00025b540?, {0x146be00?, 0xc0003fc2a0?}, 0x4732a403d5df5e84?)
	/usr/local/go/src/net/http/server.go:2220 +0x29
github.com/supabase/auth/internal/api.NewAPIWithVersion.AddRequestID.func4.1({0x146be00, 0xc0003fc2a0}, 0xc00025b540)
	/go/src/github.com/supabase/auth/internal/observability/request-logger.go:24 +0xfb
net/http.HandlerFunc.ServeHTTP(0x14701b0?, {0x146be00?, 0xc0003fc2a0?}, 0x1cc2980?)
	/usr/local/go/src/net/http/server.go:2220 +0x29
github.com/go-chi/chi/v5.(*Mux).ServeHTTP(0xc000263380, {0x146be00, 0xc0003fc2a0}, 0xc00025b400)
	/go/pkg/mod/github.com/go-chi/chi/[email protected]/mux.go:90 +0x2ee
github.com/supabase/auth/internal/api.(*router).ServeHTTP(0xc0001520d0?, {0x146be00?, 0xc0003fc2a0?}, 0xc00025b400?)
	/go/src/github.com/supabase/auth/internal/api/router.go:55 +0x28
github.com/supabase/auth/internal/api.NewAPIWithVersion.(*Cors).Handler.func9({0x146be00, 0xc0003fc2a0}, 0xc00025b400)
	/go/pkg/mod/github.com/rs/[email protected]/cors.go:289 +0x184
net/http.HandlerFunc.ServeHTTP(0xc000eb9b40?, {0x146be00?, 0xc0003fc2a0?}, 0x100c0005bc588?)
	/usr/local/go/src/net/http/server.go:2220 +0x29
github.com/supabase/auth/internal/api.(*API).ServeHTTP(0xc00071b56c?, {0x146be00?, 0xc0003fc2a0?}, 0xc000eb9b88?)
	/go/src/github.com/supabase/auth/internal/api/api.go:331 +0x25
github.com/supabase/auth/internal/reloader.(*AtomicHandler).ServeHTTP(0x410805?, {0x146be00?, 0xc0003fc2a0?}, 0xc0003fc201?)
	/go/src/github.com/supabase/auth/internal/reloader/handler.go:41 +0x71
net/http.serverHandler.ServeHTTP({0x1467ce0?}, {0x146be00?, 0xc0003fc2a0?}, 0x6?)
	/usr/local/go/src/net/http/server.go:3210 +0x8e
net/http.(*conn).serve(0xc000772090, {0x1470178, 0xc000600f30})
	/usr/local/go/src/net/http/server.go:2092 +0x5d0
created by net/http.(*Server).Serve in goroutine 1
	/usr/local/go/src/net/http/server.go:3360 +0x485

To Reproduce

I wasn't able to reproduce this locally, but we run into it consistently on production self-hosted Supabase.

  • Suspected race condition between context cancellation and response writing
  • Likely triggered by client disconnects, network timeouts, or slow database queries

Expected behavior

Either a 2xx or 4xx response from the /verify endpoint, depending on the outcome of the verification.

Screenshots

N/A

System information

  • OS: Linux
  • Browser (if applies) any
  • Version of supabase-js: Latest
  • Version of Node.js: N/A

Additional context

Race condition in timeoutMiddleware at middleware.go:392. When a request is cancelled/times out before the handler calls WriteHeader(), snapHeader remains nil, causing panic in finallyWrite() when iterating headers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions