auth icon indicating copy to clipboard operation
auth copied to clipboard

Auth service fails to start, can't create auth schema / can't execute migrations (when deployed via helm)

Open sergey-vin opened this issue 5 months ago • 2 comments

Bug report

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

Describe the bug

In short: no schema has been selected to create in error during running the migrations.

In long: Auth schema is not being created and migrations are failing to be executed when running supabase in kubernetes via helm (using official community helmchart).

I'm using as-default-as-possible settings; no tweaks are made to migrations, helm templates or anything like that.

The issue has been reported in helm's repository https://github.com/supabase-community/supabase-kubernetes/issues/86 but it seems that it's not a helm wrapper issue, and rather is related to an inconsistency in migration files + assumptions of who pre-creates auth schema, depending on how supabase and its services are being deployed.

Let's compare how differently supabase can be deployed:

Option 1. supabase CLI (all works well)

If deployed via supabase CLI (supabase init; supabase start, which spins docker-compose with several docker containers inside), then the following happens

  • db container creates schemas via the entry-point script which creates/alters some users (including supabase_auth_admin and postgres) and some non-auth related schemas, tables, functions and extensions (I couldn't find the source of this code, but something very similar has been found in https://github.com/supabase/supabase/blob/fbef43fbbcefea1cbb03c8e932681a5ad4adbcbf/docker/volumes/db/roles.sql and sibling files):
		"Entrypoint": [
			"sh",
			"-c",
			"\ncat <<'EOF' > /etc/postgresql.schema.sql && \\\ncat <<'EOF' > /etc/postgresql-custom/pgsodium_root.key && \\\ncat <<'EOF' >> /etc/postgresql/postgresql.conf && \\\ndocker-entrypoint.sh postgres -D /etc/postgresql -c search_path='$user,public,extensions'\n\\set pgpass `echo \"$PGPASSWORD\"`\n\\set jwt_secret `echo \"$JWT_SECRET\"`\n\\set jwt_exp `echo \"$JWT_EXP\"`\n\nALTER DATABASE postgres SET \"app.settings.jwt_secret\" TO :'jwt_secret';\nALTER DATABASE postgres SET \"app.settings.jwt_exp\" TO :'jwt_exp';\n\nALTER USER postgres WITH PASSWORD :'pgpass'..."
		],
  • db container also runs other init scripts from https://github.com/supabase/postgres/blob/develop/migrations/db/init-scripts/00000000000001-auth-schema.sql, which create auth schema and assign it to supabase_admin:
...
CREATE SCHEMA IF NOT EXISTS auth AUTHORIZATION supabase_admin;
...
  • auth container runs migrations from https://github.com/supabase/auth/blob/master/migrations/00_init_auth_schema.up.sql and other files. But those files are identical to the the ones that PG already executed, so auth's migrations cause a no-op:
it's already in up to date state

Option 2. supabase helm with supabase version of postgres

When running via helm, and keeping supabase's default PG instead of using RDS or other pre-existing PG, then here's what happens:

  • there's no 1st step in db pod/container - no one creates a supabase_admin role.
  • but db pod is trying to run the same scripts as in 2nd step (https://github.com/supabase/postgres/blob/develop/migrations/db/init-scripts/00000000000001-auth-schema.sql, etc):
echo "Copying init scripts into existing image script directory..."
cp -r /docker-entrypoint-initdb.d/* /initdb.d/
cp /custom-init-scripts/98-webhooks.sql /initdb.d/init-scripts/
...

which copies script files well, but fails to execute them:

92.168.135.3 2025-07-30 11:57:04.361 UTC [50] postgres@postgres ERROR:  relation "schema_migrations" does not exist at character 15
192.168.135.3 2025-07-30 11:57:04.361 UTC [50] postgres@postgres STATEMENT:  select * from schema_migrations
192.168.135.3 2025-07-30 11:57:04.363 UTC [50] postgres@postgres LOG:  statement: CREATE TABLE "schema_migrations" (
	"version" VARCHAR (14) NOT NULL,
	PRIMARY KEY("version")
	);
	CREATE UNIQUE INDEX "schema_migrations_version_idx" ON "schema_migrations" (version);
192.168.135.3 2025-07-30 11:57:04.363 UTC [50] postgres@postgres ERROR:  no schema has been selected to create in at character 14
192.168.135.3 2025-07-30 11:57:04.363 UTC [50] postgres@postgres STATEMENT:  CREATE TABLE "schema_migrations" (
	"version" VARCHAR (14) NOT NULL,
	PRIMARY KEY("version")
	);
	CREATE UNIQUE INDEX "schema_migrations_version_idx" ON "schema_migrations" (version);
192.168.99.130 2025-07-30 11:57:05.209 UTC [52] postgres@postgres LOG:  execute <unnamed>: CREATE TABLE IF NOT EXISTS "schema_migrations" ("version" bigint, "inserted_at" timestamp(0), PRIMARY KEY ("version"))
192.168.99.130 2025-07-30 11:57:05.209 UTC [52] postgres@postgres ERROR:  no schema has been selected to create in at character 28
  • and finally, when auth pod runs migrations, if fails with the same error:
{"level":"info","msg":"Go runtime metrics collection started","time":"2025-07-29T10:55:33Z"}
{"args":["20240115144230_remove_ip_address_from_saml_relay_state.sql"],"component":"pop","level":"warning","msg":"ignoring file %s because it does not match the migration file pattern","time":"2025-07-29T10:55:33Z"}
{"args":[0.015577543],"component":"pop","level":"info","msg":"%.4f seconds","time":"2025-07-29T10:55:33Z"}
{"level":"fatal","msg":"running db migrations: Migrator: problem creating schema migrations: could not execute CREATE TABLE \"schema_migrations\" (\n\"version\" VARCHAR (14) NOT NULL,\nPRIMARY KEY(\"version\")\n);\nCREATE UNIQUE INDEX \"schema_migrations_version_idx\" ON \"schema_migrations\" (version);: ERROR: no schema has been selected to create in (SQLSTATE 3F000)","time":"2025-07-29T10:55:33Z"}

Option 3. supabase helm with external postgres

this is the worst case in terms of inconsistency:

  • external db doesn't know about any special roles to be created or init scripts to be executed. even worse - there may be no access to modify its run time scripts, but even if there were, then they would not be executed, since they typically run only at the DB volume creation time, but not after
  • when auth service runs migrations, fails with the same error
ERROR: no schema has been selected to create in (SQLSTATE 3F000)

Proposal for the fix

  • remove hardcoded roles such as supabase_admin from migrations and scripts, as it may not work well with external DBs. Parametrize it.
  • instead of hardcoded supabase-cli's entrypoint script, use the script(s) from supabase/supabase repo, mounted as files and not hardcoded.
  • move all migrations out of supabase/postgres into respective services into a new migration service/job to remove duplication between PG-migrations and Auth-migrations, and to allow external DBs to be migrated as well
  • split migration process into 2
    • master migrations (which require master PG password): create roles, create schemas, do initial grants
    • auth-specific migrations (which require non-master PG password): those are the regular auth-service migrations
    • that will require passing 2 types of credentials to auth service or a migrator service (if this service will be created)

To Reproduce

(i couldn't attach a file, sorry) Before the following steps, please first save that snippet as sb-values.yaml:

secret:
  jwt:
    anonKey: "test-test-test"
    serviceKey: "test-test-test2"
    secret: "test-test-test3"
  db:
    username: "postgres"
    password: "postgres"
    database: "postgres"
  analytics:
    apiKey: "test-test-test-test"
  smtp:
    username: "user"
    password: "pass"
  dashboard:
    username: user
    password: pass

db:
  enabled: true
  image:
    repository: public.ecr.aws/supabase/postgres
    tag: "15.8.1.085"

auth:
  enabled: true
  image:
    repository: public.ecr.aws/supabase/gotrue
    pullPolicy: IfNotPresent
    tag: "v2.177.0"
  environment:
    DB_USER: postgres
    # DB_NAMESPACE: auth
    LOG_LEVEL: debug
    GOTRUE_LOG_LEVEL: debug
    
    GOTRUE_SMTP_ADMIN_EMAIL: "[email protected]"
    GOTRUE_SMTP_HOST: smtp.gmail.com
    GOTRUE_SMTP_PORT: 587
    GOTRUE_SMTP_SENDER_NAME: test

rest:
  enabled: true
  image:
    repository: public.ecr.aws/supabase/postgrest
    tag: "v12.2.12"
  environment:
    DB_USER: postgres
studio:
  enabled: true
realtime:
  enabled: false
meta:
  enabled: false
storage:
  enabled: false
imgproxy:
  enabled: false
kong:
  enabled: true
  image:
    repository: kong
    pullPolicy: IfNotPresent
    tag: "latest"
analytics:
  enabled: false
vector:
  enabled: false
functions:
  enabled: false
minio:
  enabled: false
  1. install minukube locally, or connect to any other k8s cluster
  2. install helm (e.g. brew install helm)
  3. install supabase into the cluster:
helm upgrade --install supabase vastio/supabase --namespace supabase --create-namespace -f sb-values.yaml
  1. observe that Kong, DB, Studio and Rest services are up and running, but Auth is not (see screenshot)
  2. check the Auth pod's logs (see screenshot)

Expected behavior

Regardless of using of a SB-PG DB or a pre-existing external PG DB, all migrations should have been applied and Auth service should have been running green

Screenshots

When running in kubernetes - bad:

Image

When running via supabase CLI - good:

Image Image

System information

Irrelevant

Additional context

on top of non-tweaked configs, i've also tried tweaking them a bit (tried different variations, that's why there are many similar things - i didn't know which ones are taken into account):

    DB_NAMESPACE: auth
    LOG_LEVEL: debug
    GOTRUE_LOG_LEVEL: debug
    GOTRUE_DB_DRIVER: postgres
    GOTRUE_DB_DATABASE_URL: postgresql://postgres:postgres@supabase-supabase-db:5432/postgres
    DB_AFTER_CONNECT_QUERY: "SET search_path TO auth,public"
    GOTRUE_DB_AFTER_CONNECT_QUERY: "SET search_path TO auth,public"
    PGOPTIONS: -c search_path=auth,public
    GOTRUE_PGOPTIONS: -c search_path=auth,public
    GOTRUE_PG_OPTIONS: -c search_path=auth,public
    GOTRUE_DB_PGOPTIONS: -c search_path=auth,public
    GOTRUE_DB_PG_OPTIONS: -c search_path=auth,public

And that caused a migration process to progress a bit further along: it stopped looking for non-existant auth, and moved on to public, created migrations table there but stopped on some other issue later on.

But that confirms that the auth schema is expected to be pre-created before auth service could run its migrations, and it makes it hard to run supabase stack outside of tuned supabase cli environment.

sergey-vin avatar Jul 30 '25 12:07 sergey-vin