stablyai/orca · error · Error

invalid_orca_org_member_user

Error message

invalid_orca_org_member_user

What it means

Thrown by orgUserIdFromUnknown() when the userId field of a role-change or remove-member payload is missing, not a string, or trims to empty. The userId is the cloud account id of the target member (not an email); it must originate from the members list returned by orcaProfiles:orgMembersList.

Source

Thrown at src/main/ipc/orca-profile-org-members-handlers.ts:51

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
}

function orgMemberInviteArgsFromUnknown(args: unknown): OrcaProfileOrgMemberInviteArgs {
  const { orgId, record } = orgMembersScopedArgs(args)
  return { orgId, email: orgEmailFromUnknown(record.email), role: orgRoleFromUnknown(record.role) }
}

function orgInviteRevokeArgsFromUnknown(args: unknown): OrcaProfileOrgInviteRevokeArgs {
  const { orgId, record } = orgMembersScopedArgs(args)
  return { orgId, email: orgEmailFromUnknown(record.email) }
}

function orgMemberChangeRoleArgsFromUnknown(args: unknown): OrcaProfileOrgMemberChangeRoleArgs {
  const { orgId, record } = orgMembersScopedArgs(args)
  return {
    orgId,

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Pass member.userId from the selected row of the orgMembersList result, not a display name or email.
  2. Disable the change-role / remove buttons in the UI until exactly one member row is selected.
  3. Verify the list response shape (member.userId) matches what the action reads — they must use the same key name.
  4. After any orgMembersList refetch, clear the selection rather than carrying a stale userId forward.

Example fix

// before
await ipcRenderer.invoke('orcaProfiles:orgMemberRemove', { orgId, userId: selectedMember?.id })

// after
const userId = selectedMember?.userId?.trim()
if (!userId) return
await ipcRenderer.invoke('orcaProfiles:orgMemberRemove', { orgId, userId })
Defensive patterns

Strategy: validation

Validate before calling

function isSelectedMember(v: unknown): v is { userId: string } {
  return (
    typeof v === 'object' &&
    v !== null &&
    typeof (v as { userId?: unknown }).userId === 'string' &&
    (v as { userId: string }).userId.trim() !== ''
  )
}

if (!isSelectedMember(selectedMember)) return

Type guard

function isMemberWithUserId(v: unknown): v is { userId: string } {
  return (
    !!v &&
    typeof v === 'object' &&
    typeof (v as { userId?: unknown }).userId === 'string' &&
    (v as { userId: string }).userId.trim() !== ''
  )
}

Try / catch

try {
  await ipcRenderer.invoke('orcaProfiles:orgMemberRemove', { orgId, userId })
} catch (e) {
  if (e instanceof Error && e.message === 'invalid_orca_org_member_user') {
    setMemberError('Select a member first.')
  } else throw e
}

Prevention

When it happens

Trigger: Calling orcaProfiles:orgMemberChangeRole or orcaProfiles:orgMemberRemove with record.userId unset, null, or whitespace, e.g. dispatching a remove before a member row is selected.

Common situations: A member row was deselected before the action fired, the row's userId field was renamed in the list response shape but the action payload still reads the old key, or a list refresh replaced members with a fresh fetch whose id field is named differently.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/328f602812420edc. Report an issue: GitHub.