different-ai/openwork · error
member_not_found (Error; invalid desktop policy member IDs)
Error message
member_not_found (Error; invalid desktop policy member IDs)
What it means
resolveMemberIds validates that every member ID supplied for a desktop policy exists in the given organization and has not been removed. It queries MemberTable filtered by organizationId, the supplied IDs, and removedAt IS NULL; if the matched row count differs from the input count, it throws Error("member_not_found").
Source
Thrown at ee/apps/den-api/src/routes/org/desktop-policies.ts:87
function resolveRoles(values: DesktopPolicyAssignmentRole[]) {
return [...new Set(values)]
}
async function resolveMemberIds(input: {
organizationId: typeof DesktopPolicyTable.$inferSelect.organizationId
values: string[]
}) {
const memberIds = [...new Set(input.values)].map(parseMemberId)
if (memberIds.length === 0) return [] as MemberId[]
const rows = await db
.select({ id: MemberTable.id })
.from(MemberTable)
.where(and(eq(MemberTable.organizationId, input.organizationId), inArray(MemberTable.id, memberIds), isNull(MemberTable.removedAt)))
if (rows.length !== memberIds.length) {
throw new Error("member_not_found")
}
return memberIds
}
async function resolveTeamIds(input: {
organizationId: typeof DesktopPolicyTable.$inferSelect.organizationId
values: string[]
}) {
const teamIds = [...new Set(input.values)].map(parseTeamId)
if (teamIds.length === 0) return [] as TeamId[]
const rows = await db
.select({ id: TeamTable.id })
.from(TeamTable)
.where(and(eq(TeamTable.organizationId, input.organizationId), inArray(TeamTable.id, teamIds)))
if (rows.length !== teamIds.length) {View on GitHub (pinned to 2b7df46e8a)
Solutions
- Before saving, verify each member ID via GET org members and drop IDs that no longer resolve.
- Refresh the member picker data so removed members are excluded from the submission.
- If a member was re-added, use their NEW member ID — the old MemberTable row is tombstoned with removedAt.
- Confirm the IDs belong to the same organizationId as the policy being written.
Example fix
// before memberIds: ["mem_1", "mem_removed"] // throws member_not_found // after const valid = await listOrgMembers(orgId) memberIds: ["mem_1", ...].filter(id => valid.some(m => m.id === id && !m.removedAt))
Defensive patterns
Strategy: validation
Validate before calling
const ids = payload.memberIds
const rows = await db.select({ id: MemberTable.id }).from(MemberTable)
.where(and(eq(MemberTable.organizationId, orgId), inArray(MemberTable.id, ids), isNull(MemberTable.removedAt)))
if (rows.length !== ids.length) {
throw new Error(`Unknown/removed member IDs: ${ids.filter(i => !rows.some(r => r.id === i)).join(", ")}`)
} Type guard
function allMembersActive(ids: string[], members: Array<{ id: string; removedAt: Date | null }>): boolean {
return ids.every(id => members.some(m => m.id === id && m.removedAt === null))
} Try / catch
try {
await saveDesktopPolicy(orgId, { memberIds, ...rest })
} catch (e) {
if (e instanceof Error && e.message === "member_not_found") {
const fresh = await listOrgMembers(orgId)
return saveDesktopPolicy(orgId, { memberIds: memberIds.filter(id => fresh.some(m => m.id === id)), ...rest })
}
throw e
} Prevention
- Refresh member lists in the UI before submitting policy changes
- Drop removed members (removedAt != null) from stored policy drafts
- Scope all member ID lookups to the policy's organizationId
- Use the new member ID if a removed member is re-added
When it happens
Trigger: Creating/updating an org desktop policy with memberIds containing an ID from another organization, a deleted/nonexistent member, or a member whose removedAt is set (removed from the org).
Common situations: Client UI caching member IDs after a member was removed; copying policy JSON between orgs; a member deactivated between fetching the form and submitting; typos or stale test fixtures in API calls.
Related errors
- team_not_found (Error; invalid desktop policy team IDs)
- The owner role cannot be assigned from this action.
- Agent context diagnostics timeout must be between 1 ms and 3
- Invalid cloud provider sync response.
- Invalid cloud provider sync status.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/6ab130bf0a2bf79b.
Report an issue: GitHub.