JuliusBrussee/caveman · error

postgres: expected runtime role is required

Error message

postgres: expected runtime role is required

What it means

ValidateRuntimeIdentity checks that the pool's database user cannot bypass RLS and belongs to the expected audited role group; it refuses to run that check at all when expectedRole is blank. An empty expected role would make the membership assertion vacuous, so the library fails fast before issuing any query.

Solutions

  1. Pass the intended database role name, e.g. ValidateRuntimeIdentity(ctx, pool, "svc_orders_runtime")
  2. Populate the role from configuration and fail deployment earlier if it is missing
  3. Trim and check the role string at config-load time so this reaches the caller as a config error

Example fix

// before
if err := ValidateRuntimeIdentity(ctx, pool, os.Getenv("PG_ROLE")); err != nil {...} // PG_ROLE unset
// after
role := os.Getenv("PG_ROLE")
if strings.TrimSpace(role) == "" { return fmt.Errorf("PG_ROLE must be set") }
if err := ValidateRuntimeIdentity(ctx, pool, role); err != nil {...}
Defensive patterns

Strategy: validation

Validate before calling

role := strings.TrimSpace(expectedRole)
if role == "" {
    return fmt.Errorf("expected runtime role must be configured before ValidateRuntimeIdentity")
}

Try / catch

if err := postgresconfig.ValidateRuntimeIdentity(ctx, pool, role); err != nil {
    if strings.Contains(err.Error(), "expected runtime role is required") {
        return fmt.Errorf("runtime role not configured: set PG_ROLE before starting")
    }
    return err
}

Prevention

When it happens

Trigger: Calling ValidateRuntimeIdentity(ctx, pool, "") or with a whitespace-only string (spaces/tabs are trimmed to empty); passing a config value that was never populated, e.g. an unset ROLE env var defaulted to "".

Common situations: New services wired to NewRuntimePool before the runtime-role config key was added; template manifests rendering an empty role; tests forgetting to pass the role constant.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

		return nil, err
	}
	if err := ValidateRuntimeIdentity(ctx, pool, expectedRole); err != nil {
		pool.Close()
		return nil, err
	}
	if err := ValidateTenantSchema(ctx, pool); err != nil {
		pool.Close()
		return nil, err
	}
	return pool, nil
}

// ValidateRuntimeIdentity rejects database identities that can bypass RLS or
// do not inherit the service's audited privilege group.
func ValidateRuntimeIdentity(ctx context.Context, pool *pgxpool.Pool, expectedRole string) error {
	expectedRole = strings.TrimSpace(expectedRole)
	if expectedRole == "" {
		return errors.New("postgres: expected runtime role is required")
	}
	var currentUser, sessionUser string
	var superuser, bypassRLS, member, ownsTenantTable bool
	err := pool.QueryRow(ctx, `
		SELECT current_user,
		       session_user,
		       r.rolsuper,
		       r.rolbypassrls,
		       pg_has_role(current_user, $1, 'MEMBER'),
		       EXISTS (
		         SELECT 1
		         FROM pg_class c
		         JOIN pg_namespace n ON n.oid=c.relnamespace
		         JOIN information_schema.columns col
		           ON col.table_schema=n.nspname
		          AND col.table_name=c.relname
		          AND col.column_name='organization_id'
		         WHERE n.nspname='public'

View on GitHub (pinned to 3ee70a1026)