JuliusBrussee/caveman · error

postgres: finish tenant schema inspection

Error message

postgres: finish tenant schema inspection: %w

What it means

ValidateTenantSchema performs its checks inside a transaction and commits at the end. This error wraps a failure of that final tx.Commit. All inspections and validations already passed; only persisting (committing) the read-only inspection transaction failed.

Solutions

  1. Check the wrapped error for 'context canceled/deadline' and increase the startup context timeout
  2. Check server logs / idle-in-transaction-timeout settings; speed up inspection or raise the timeout
  3. Verify network stability between app and Postgres
  4. Since the inspection is read-only, simply retry pool creation after fixing the connection
Defensive patterns

Strategy: retry

Try / catch

var lastErr error
for i := 0; i < 3; i++ {
    if err := NewRuntimePool(ctx, cfg); err != nil {
        if strings.Contains(err.Error(), "finish tenant schema inspection") && errors.Is(err, context.DeadlineExceeded) {
            lastErr = err; time.Sleep(backoff(i)); continue
        }
        return err
    }
    break
}

Prevention

When it happens

Trigger: NewRuntimePool → ValidateTenantSchema: the inspection transaction completes its queries, but tx.Commit returns an error — connection lost during commit, context canceled before commit completed, or the server aborted the transaction.

Common situations: Idle-in-transaction timeout on the server while slow catalog queries ran; network drop between last query and Commit; context deadline exceeded during a long startup; Postgres restart mid-inspection.

Related errors


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

Appendix: source

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

	}
	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) {
	rows, err := queryer.Query(ctx, `
		SELECT c.relname,
		       NOT organization.attnotnull,
		       c.relrowsecurity,
		       c.relforcerowsecurity,
		       pol.oid IS NOT NULL,
		       coalesce(pol.polpermissive, false),
		       coalesce(pol.polcmd::text, ''),
		       coalesce(pol.polroles=ARRAY[0::oid], false),
		       coalesce(pg_get_expr(pol.polqual, pol.polrelid), ''),
		       coalesce(pg_get_expr(pol.polwithcheck, pol.polrelid), '')
		FROM pg_class c
		JOIN pg_namespace n ON n.oid=c.relnamespace

View on GitHub (pinned to 3ee70a1026)