Skip to content

declarative sync: "permission denied for table schema_migrations" when the shadow's Realtime sidecar creates _realtime.* before the data-statement probe (2.116.0) #6453

Description

@bttf

Describe the bug

supabase --experimental db schema declarative sync --no-apply -f <name> fails on CLI 2.116.0 with:

{"_tag":"Error","error":{"code":"LegacyPgDeltaEngineError","message":"Declarative schema planning failed: permission denied for table schema_migrations"}}

It fails on an unmodified checkout whose migrations and declarative files are in sync, and on the same tree that generated a migration successfully with the same CLI the day before. The migrations shadow builds fine; the failure is in the second (declarative) shadow.

The shadow database's Postgres log shows the failing statement and role:

postgres@postgres ERROR:  permission denied for table schema_migrations
postgres@postgres STATEMENT:  SELECT EXISTS (SELECT 1 FROM "_realtime"."schema_migrations" LIMIT 1) AS has

Cause (from reading the bundled engine)

The declarative load step checks that the schema files contain no data statements by listing every regular, non-extension table in the shadow (pg_class with relkind = 'r') and running SELECT EXISTS (SELECT 1 FROM <table> LIMIT 1) on each, as the postgres role. The check runs before and after the files are applied (the "managed user table ... contains rows after loading the declarative files" validation).

The shadow's Realtime sidecar creates _realtime.schema_migrations, _realtime.tenants and _realtime.extensions as supabase_admin with no grants (relacl is null), and postgres is not a superuser in the local image. So as soon as Realtime has finished its own migrations before the probe runs, the probe throws. Whether that happens is a race with the sidecar's boot, which is why the same tree can pass one day and fail the next. In the run above Realtime finished about 2 s after the shadow was ready and the probe ran about 4 s after.

The _realtime schema is already on the engine's managed-schema list, so the probe has no reason to touch it.

To Reproduce

  1. CLI 2.116.0 (Homebrew or npm), Docker Desktop on macOS, [realtime] enabled = true (the default) in config.toml, schema_paths = ["./schemas/*.sql"].
  2. Any project whose migrations and declarative files are in sync.
  3. supabase --experimental db schema declarative sync --no-apply -f probe
  4. Observe the error above. --no-cache and --schema public do not change it.

Confirming the cause: set [realtime] enabled = false, rerun step 3, it reports No schema changes found.

Expected behavior

The data-statement probe should skip managed/platform schemas (or tables the connecting role cannot read), or run as supabase_admin, so the declarative sync does not depend on the Realtime sidecar's boot timing.

System information

  • OS: macOS 26 (Darwin 25.6.0), arm64
  • Supabase CLI 2.116.0
  • Docker Desktop, engine 28.0.1
  • Postgres image supabase/postgres:17.6.1.071, Realtime v2.129.3

Workaround

Disable Realtime in config.toml for the duration of the sync, then revert the file.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions