Skip to content

EQL v2 Supabase / no-operator-family install fails on non-superuser roles (out-of-order DDL) #599

Description

@coderdan

Summary

stash eql install --supabase (and the --no-operator-family fallback) fails on any non-superuser Postgres role with type eql_v2_encrypted does not exist. On local Supabase the app role is postgres, which is not a superuser (only supabase_admin is), so the supported Supabase EQL install path is broken out of the box.

Environment

  • stash 0.17.1 · @cipherstash/stack 0.19.0 · bundled EQL eql-2.3.1
  • Local Supabase Postgres, postgres role (non-superuser)

Repro

# DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
npx stash eql install --supabase
npx stash eql install --supabase --direct --force
npx stash eql install --force        # auto-detects non-superuser -> no-operator-family fallback

All fail:

■  Fatal error: Failed to install EQL: type eql_v2_encrypted does not exist

Root cause

The installer runs the whole bundle as a single in-order transaction (stash/dist/bin/main-*.js, install(): BEGINclient.query(sql) → grants → COMMIT), so statement order is load-bearing. In the no-operator-family bundles the composite type is created after the function/cast that consume it:

stash/dist/sql/cipherstash-encrypt-supabase.sql (identical offsets in cipherstash-encrypt-no-operator-family.sql):

line statement
156 CREATE FUNCTION eql_v2.to_stevec_query(e eql_v2_encrypted) ... ← uses the type
178 CREATE CAST (eql_v2_encrypted AS eql_v2.stevec_query) ... ← uses the type
201 CREATE TYPE public.eql_v2_encrypted AS ( data jsonb ) ← creates it, too late

The operator-family bundle cipherstash-encrypt.sql is ordered correctly (type at line 38) but requires superuser (for the operator family). So on Supabase (non-superuser) every bundle the CLI selects is broken. The SQL bundle ships with the CLI but originates from encrypt-query-language — the templating that strips the operator-family section to produce the -supabase / -no-operator-family variants also drops the early CREATE TYPE, leaving only the late one.

Suggested fix

Move CREATE TYPE public.eql_v2_encrypted to the top of the -supabase / -no-operator-family bundles (before the function/cast that use it), matching the ordering already used in cipherstash-encrypt.sql.

Workaround

Pre-create just that one IF NOT EXISTS-guarded type, then re-run stash eql install (the CLI still installs all 196 eql_v2 functions):

DO $$ BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'eql_v2_encrypted') THEN
    CREATE TYPE public.eql_v2_encrypted AS (data jsonb);
  END IF;
END $$;

Found via a CipherStash integration eval on cipherstash/supabase-nextjs-starter (hono-pg surface). Full report: https://github.com/cipherstash/supabase-nextjs-starter/blob/feat/multi-surface-starters/docs/evals/hono-pg/2026-07-09-bug-eql-supabase-install-ordering.md

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions