plandex-ai/plandex · error

error getting org owners: %v

Error message

error getting org owners: %v

What it means

GetOrgOwners queries users whose orgs_users row has the owner role for the given org. The SELECT failed at the database level, so the raw driver error is wrapped with this message. Note the query reads the package global orgOwnerRoleId directly without ensuring it is cached, so it can also silently query with an empty role id (returning no owners) when caching never ran.

Source

Thrown at app/server/db/rbac_helpers.go:46

		err := cacheOrgMemberRoleId()
		if err != nil {
			return "", fmt.Errorf("error getting org member role id: %v", err)
		}
	}

	if orgMemberRoleId == "" {
		return "", fmt.Errorf("org member role id is empty")
	}

	return orgMemberRoleId, nil
}

func GetOrgOwners(orgId string) ([]*User, error) {
	var users []*User
	err := Conn.Select(&users, "SELECT * FROM users WHERE id IN (SELECT user_id FROM orgs_users WHERE org_id = $1 AND org_role_id = $2)", orgId, orgOwnerRoleId)

	if err != nil {
		return nil, fmt.Errorf("error getting org owners: %v", err)
	}

	return users, nil
}

func CacheOrgRoleIds() error {
	err := cacheOrgOwnerRoleId()
	if err != nil {
		return fmt.Errorf("error getting org owner role id: %v", err)

	}

	if orgOwnerRoleId == "" {
		log.Println("org owner role id is empty at startup")
	}

	err = cacheOrgMemberRoleId()
	if err != nil {

View on GitHub (pinned to e2d772072e)

Solutions

  1. Call GetOrgOwnerRoleId() first and pass its result explicitly instead of the raw global
  2. Confirm CacheOrgRoleIds() ran at startup
  3. Check DB connectivity and the wrapped inner error
  4. Validate orgId is a valid, existing org id

Example fix

// before
err := Conn.Select(&users, "SELECT * FROM users WHERE id IN (SELECT user_id FROM orgs_users WHERE org_id = $1 AND org_role_id = $2)", orgId, orgOwnerRoleId)
// after
ownerRoleId, err := GetOrgOwnerRoleId()
if err != nil {
	return nil, err
}
err = Conn.Select(&users, "SELECT * FROM users WHERE id IN (SELECT user_id FROM orgs_users WHERE org_id = $1 AND org_role_id = $2)", orgId, ownerRoleId)
Defensive patterns

Strategy: validation

Validate before calling

// ensure cache is populated before calling GetOrgOwners
if err := CacheOrgRoleIds(); err != nil {
	return err
}
owners, err := GetOrgOwners(orgId)

Type guard

func orgCacheReady() bool { return orgOwnerRoleId != "" }

func canListOwners(orgId string) bool {
	return orgId != "" && orgCacheReady()
}

Try / catch

owners, err := GetOrgOwners(orgId)
if err != nil {
	log.Printf("GetOrgOwners failed for org %s: %v", orgId, err)
	return nil, fmt.Errorf("owner lookup unavailable: %w", err)
}
if len(owners) == 0 {
	log.Printf("warning: org %s has no owners (role id may be uncached)", orgId)
}

Prevention

When it happens

Trigger: Calling GetOrgOwners with an unreachable database, malformed query parameters, or before CacheOrgRoleIds populated orgOwnerRoleId (empty $2 yields zero owners instead of this error).

Common situations: DB outage during admin listing; calling the function in a fresh process before MustInitDb; orgId format mismatch (e.g. int vs uuid string) causing a SQL type error.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/92f5bf61e91d3a75. Report an issue: GitHub.