stablyai/orca · error · Error
invalid_orca_org_role
Error message
invalid_orca_org_role
What it means
Thrown by orgRoleFromUnknown() when the role value on an invite or role-change payload is not one of the literal string values 'owner', 'admin', or 'member'. The function narrows an untrusted renderer input to the OrcaOrgRole union; any other value (including typos like 'Owner' with capital, 'guest', numbers, or undefined) is rejected before reaching the cloud org-members service.
Source
Thrown at src/main/ipc/orca-profile-org-members-handlers.ts:37
} from '../orca-profiles/profile-cloud-org-members-service'
function orgMembersScopedArgs(args: unknown): { orgId: string; record: Record<string, unknown> } {
if (!args || typeof args !== 'object') {
throw new Error('invalid_orca_profile_org_selection')
}
const record = args as Record<string, unknown>
const orgId = typeof record.orgId === 'string' ? record.orgId.trim() : ''
if (!orgId) {
throw new Error('invalid_orca_profile_org_selection')
}
return { orgId, record }
}
function orgRoleFromUnknown(value: unknown): OrcaOrgRole {
if (value === 'owner' || value === 'admin' || value === 'member') {
return value
}
throw new Error('invalid_orca_org_role')
}
function orgEmailFromUnknown(value: unknown): string {
const email = typeof value === 'string' ? value.trim() : ''
if (!email) {
throw new Error('invalid_orca_org_member_email')
}
return email
}
function orgUserIdFromUnknown(value: unknown): string {
const userId = typeof value === 'string' ? value.trim() : ''
if (!userId) {
throw new Error('invalid_orca_org_member_user')
}
return userId
}
View on GitHub (pinned to 1136503c6a)
Solutions
- Send the lowercase canonical role string exactly: 'owner' | 'admin' | 'member' — no capitalization, no synonyms.
- Map UI role labels to canonical ids at the dropdown boundary and pass the id, not the label.
- If a new role is genuinely supported upstream, add it to the literal union in shared/orca-profiles (OrcaOrgRole) and to this guard in lockstep.
- Default the invite role to 'member' when the picker has no explicit selection, rather than sending undefined.
Example fix
// before
await ipcRenderer.invoke('orcaProfiles:orgMemberInvite', { orgId, email, role: roleSelect.value })
// after
const ROLES = ['owner', 'admin', 'member'] as const
const role = ROLES.includes(roleSelect.value) ? roleSelect.value : 'member'
await ipcRenderer.invoke('orcaProfiles:orgMemberInvite', { orgId, email, role }) Defensive patterns
Strategy: type-guard
Validate before calling
const ORG_ROLES = ['owner', 'admin', 'member'] as const
type OrgRole = typeof ORG_ROLES[number]
function toOrgRole(v: unknown): OrgRole {
return ORG_ROLES.includes(v as OrgRole) ? (v as OrgRole) : 'member'
} Type guard
function isOrgRole(v: unknown): v is 'owner' | 'admin' | 'member' {
return v === 'owner' || v === 'admin' || v === 'member'
} Try / catch
try {
await ipcRenderer.invoke('orcaProfiles:orgMemberInvite', { orgId, email, role })
} catch (e) {
if (e instanceof Error && e.message === 'invalid_orca_org_role') {
setRoleError('Role must be owner, admin, or member.')
} else throw e
} Prevention
- Render the role dropdown from the same constant array the guard uses.
- Map UI labels to canonical role ids at the select boundary.
- When adding a cloud role, update the OrcaOrgRole union and this guard atomically.
When it happens
Trigger: Calling orcaProfiles:orgMemberInvite or orcaProfiles:orgMemberChangeRole with a role field that is missing, undefined, or any string other than exactly 'owner', 'admin', or 'member'. Capitalized variants and synonyms are rejected.
Common situations: Role dropdown emits a display label ('Administrator') instead of the canonical value, a serialized enum from a different schema leaks in, or a new role was added to the cloud API but the main-process allowlist has not been updated.
Related errors
- invalid_orca_org_member_email
- invalid_orca_org_member_user
- invalid_orca_profile_id
- invalid_orca_profile_project_transfer
- invalid_orca_profile_project_path
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/fbc09b7a16bb5824.
Report an issue: GitHub.