JuliusBrussee/caveman · error

postgres: inspect tenant tables

Error message

postgres: inspect tenant tables: %w

What it means

ValidateTenantSchema opens a transaction and runs catalog queries to enumerate the tenant schema's tables. This error wraps any failure while executing inspectTenantTables against pg_catalog during that inspection. It means the introspection query itself failed (connection, permissions, or query error), not that the schema is wrong.

Solutions

  1. Verify the Postgres role used by the pool has permission to read catalog tables (SELECT on information_schema.tables, pg_catalog.pg_class, etc.)
  2. Check the underlying wrapped error (%w) for context canceled / connection errors and fix connectivity or increase startup timeouts
  3. Confirm the DSN points to the correct Postgres instance and version
  4. Retry pool creation if the cause was a transient network failure

Example fix

// before
pool, err := NewRuntimePool(ctx, cfg) // fails: postgres: inspect tenant tables
// after
// grant catalog read to the app role first, then:
// GRANT SELECT ON information_schema.tables TO app_role;
pool, err := NewRuntimePool(ctx, cfg)
Defensive patterns

Strategy: try-catch

Validate before calling

if err := pool.Ping(ctx); err != nil { return fmt.Errorf("db unreachable before pool init: %w", err) }

Try / catch

if err := NewRuntimePool(ctx, cfg); err != nil {
    var opErr *pgconn.ConnectError
    if errors.As(err, &opErr) || errors.Is(err, context.DeadlineExceeded) {
        // retry with backoff or fail startup with a clear message
    }
    return err
}

Prevention

When it happens

Trigger: Calling NewRuntimePool (which calls ValidateTenantSchema) when the catalog query in inspectTenantTables cannot be executed: the tx.Query in inspectTenantTables returns an error such as canceled context, permission denied on system catalogs, or a driver/connection failure.

Common situations: Database user lacks SELECT on pg_catalog/information_schema; context canceled mid-startup because the pool init is slow or shut down; transient network drop between Begin and the inspection query; misconfigured DSN pointing at a non-Postgres server that rejects the query.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/6af40bafa9156105. Report an issue: GitHub.

Appendix: source

Thrown at shared/platform/postgresconfig/postgresconfig.go:238

var organizationPolicyExpression = regexp.MustCompile(`^organization_id=\(*current_setting\('app\.current_organization_id'(?:::text)?(?:,true)?\)\)*(?:::[A-Za-z_][A-Za-z0-9_.$"]*)?$`)

// ValidateTenantSchema proves structural isolation invariants that are easy to
// regress during schema evolution. Every tenant table must fail closed under
// FORCE RLS, and every foreign-key edge between tenant tables must carry the
// shared organization scope (plus project scope when both tables have it).
func ValidateTenantSchema(ctx context.Context, pool *pgxpool.Pool) error {
	tx, err := pool.BeginTx(ctx, pgx.TxOptions{
		IsoLevel:   pgx.RepeatableRead,
		AccessMode: pgx.ReadOnly,
	})
	if err != nil {
		return fmt.Errorf("postgres: begin tenant schema inspection: %w", err)
	}
	defer tx.Rollback(ctx)

	tables, err := inspectTenantTables(ctx, tx)
	if err != nil {
		return fmt.Errorf("postgres: inspect tenant tables: %w", err)
	}
	foreignKeys, err := inspectTenantForeignKeys(ctx, tx)
	if err != nil {
		return fmt.Errorf("postgres: inspect tenant foreign keys: %w", err)
	}
	if violations := tenantSchemaViolations(tables, foreignKeys); len(violations) > 0 {
		return fmt.Errorf("postgres: tenant schema isolation incomplete: %s", strings.Join(violations, "; "))
	}
	if err := validateResolverSchema(ctx, tx); err != nil {
		return err
	}
	if err := tx.Commit(ctx); err != nil {
		return fmt.Errorf("postgres: finish tenant schema inspection: %w", err)
	}
	return nil
}

func inspectTenantTables(ctx context.Context, queryer catalogQuerier) ([]tenantTableSchema, error) {

View on GitHub (pinned to 3ee70a1026)