different-ai/openwork · error

team_not_found (Error; invalid desktop policy team IDs)

Error message

team_not_found (Error; invalid desktop policy team IDs)

What it means

resolveTeamIds validates team IDs supplied for a desktop policy the same way resolveMemberIds validates members: it selects TeamTable rows matching the organizationId and the given IDs, and throws Error("team_not_found") when any ID does not resolve to an existing team in that organization.

Source

Thrown at ee/apps/den-api/src/routes/org/desktop-policies.ts:106

  }

  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) {
    throw new Error("team_not_found")
  }

  return teamIds
}

async function loadDesktopPolicies(organizationId: typeof DesktopPolicyTable.$inferSelect.organizationId) {
  const policies = await db
    .select()
    .from(DesktopPolicyTable)
    .where(and(eq(DesktopPolicyTable.organizationId, organizationId), isNull(DesktopPolicyTable.deletedAt)))
    .orderBy(desc(DesktopPolicyTable.isDefault), asc(DesktopPolicyTable.policyName))

  if (policies.length === 0) return []

  const policyIds = policies.map((policy) => policy.id)
  const assignments = await db
    .select({
      id: DesktopPolicyMemberTable.id,

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Fetch the current team list for the organization and filter the payload to existing team IDs before saving.
  2. Reload the policy editor after team deletions so stale IDs are dropped.
  3. Verify team IDs are scoped to the same organizationId as the desktop policy.
  4. On failure, re-read the server's current policy state and resubmit a corrected payload.

Example fix

// before
teamIds: ["team_a", "team_deleted"] // throws team_not_found
// after
const teams = await listOrgTeams(orgId)
teamIds: ["team_a"].filter(id => teams.some(t => t.id === id))
Defensive patterns

Strategy: validation

Validate before calling

const ids = payload.teamIds
const rows = await db.select({ id: TeamTable.id }).from(TeamTable)
  .where(and(eq(TeamTable.organizationId, orgId), inArray(TeamTable.id, ids)))
if (rows.length !== ids.length) {
  throw new Error(`Unknown team IDs: ${ids.filter(i => !rows.some(r => r.id === i)).join(", ")}`)
}

Type guard

function allTeamsExist(ids: string[], teams: Array<{ id: string }>): boolean {
  return ids.every(id => teams.some(t => t.id === id))
}

Try / catch

try {
  await saveDesktopPolicy(orgId, { teamIds, ...rest })
} catch (e) {
  if (e instanceof Error && e.message === "team_not_found") {
    const fresh = await listOrgTeams(orgId)
    return saveDesktopPolicy(orgId, { teamIds: teamIds.filter(id => fresh.some(t => t.id === id)), ...rest })
  }
  throw e
}

Prevention

When it happens

Trigger: Saving a desktop policy whose teamIds include a nonexistent team, a team belonging to a different organization, or a team deleted before submission.

Common situations: Stale team list in the admin UI after a team was deleted; policy templates shared across organizations; concurrent deletion of a team while another admin edits the policy; automated scripts replaying old policy payloads.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/d4c684659d0c098e. Report an issue: GitHub.