{"record":{"id":"d4c684659d0c098e","repo":"different-ai/openwork","slug":"team-not-found-error-invalid-desktop-policy-team","errorCode":null,"errorMessage":"team_not_found (Error; invalid desktop policy team IDs)","messagePattern":"team_not_found \\(Error; invalid desktop policy team IDs\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-api/src/routes/org/desktop-policies.ts","lineNumber":106,"sourceCode":"  }\n\n  return memberIds\n}\n\nasync function resolveTeamIds(input: {\n  organizationId: typeof DesktopPolicyTable.$inferSelect.organizationId\n  values: string[]\n}) {\n  const teamIds = [...new Set(input.values)].map(parseTeamId)\n  if (teamIds.length === 0) return [] as TeamId[]\n\n  const rows = await db\n    .select({ id: TeamTable.id })\n    .from(TeamTable)\n    .where(and(eq(TeamTable.organizationId, input.organizationId), inArray(TeamTable.id, teamIds)))\n\n  if (rows.length !== teamIds.length) {\n    throw new Error(\"team_not_found\")\n  }\n\n  return teamIds\n}\n\nasync function loadDesktopPolicies(organizationId: typeof DesktopPolicyTable.$inferSelect.organizationId) {\n  const policies = await db\n    .select()\n    .from(DesktopPolicyTable)\n    .where(and(eq(DesktopPolicyTable.organizationId, organizationId), isNull(DesktopPolicyTable.deletedAt)))\n    .orderBy(desc(DesktopPolicyTable.isDefault), asc(DesktopPolicyTable.policyName))\n\n  if (policies.length === 0) return []\n\n  const policyIds = policies.map((policy) => policy.id)\n  const assignments = await db\n    .select({\n      id: DesktopPolicyMemberTable.id,","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/routes/org/desktop-policies.ts#L88-L124","documentation":"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.","triggerScenarios":"Saving a desktop policy whose teamIds include a nonexistent team, a team belonging to a different organization, or a team deleted before submission.","commonSituations":"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.","solutions":["Fetch the current team list for the organization and filter the payload to existing team IDs before saving.","Reload the policy editor after team deletions so stale IDs are dropped.","Verify team IDs are scoped to the same organizationId as the desktop policy.","On failure, re-read the server's current policy state and resubmit a corrected payload."],"exampleFix":"// before\nteamIds: [\"team_a\", \"team_deleted\"] // throws team_not_found\n// after\nconst teams = await listOrgTeams(orgId)\nteamIds: [\"team_a\"].filter(id => teams.some(t => t.id === id))","handlingStrategy":"validation","validationCode":"const ids = payload.teamIds\nconst rows = await db.select({ id: TeamTable.id }).from(TeamTable)\n  .where(and(eq(TeamTable.organizationId, orgId), inArray(TeamTable.id, ids)))\nif (rows.length !== ids.length) {\n  throw new Error(`Unknown team IDs: ${ids.filter(i => !rows.some(r => r.id === i)).join(\", \")}`)\n}","typeGuard":"function allTeamsExist(ids: string[], teams: Array<{ id: string }>): boolean {\n  return ids.every(id => teams.some(t => t.id === id))\n}","tryCatchPattern":"try {\n  await saveDesktopPolicy(orgId, { teamIds, ...rest })\n} catch (e) {\n  if (e instanceof Error && e.message === \"team_not_found\") {\n    const fresh = await listOrgTeams(orgId)\n    return saveDesktopPolicy(orgId, { teamIds: teamIds.filter(id => fresh.some(t => t.id === id)), ...rest })\n  }\n  throw e\n}","preventionTips":["Reload the team list in the admin UI after any team create/delete","Filter saved policy drafts against the current team list before submission","Scope team ID lookups to the policy's organizationId","Handle concurrent team deletion with a resubmit-after-refresh flow"],"tags":["validation","policy","organization","teams"],"backgroundTag":"referenced-entity-not-found","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}