{"record":{"id":"e6e31332eb46890d","repo":"different-ai/openwork","slug":"automation-owner-inactive","errorCode":"automation_owner_inactive","errorMessage":"automation_owner_inactive","messagePattern":"automation_owner_inactive","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-api/src/workflows.ts","lineNumber":523,"sourceCode":"}\n\nexport async function validateWorkflowAutomationAction(input: {\n  organizationId: string\n  ownerMemberId: string\n  action: Extract<AutomationAction, { kind: \"saved_script\" }>\n}) {\n  const organizationId = normalizeDenTypeId(\"organization\", input.organizationId)\n  const ownerMemberId = normalizeDenTypeId(\"member\", input.ownerMemberId)\n  const pluginId = normalizeDenTypeId(\"plugin\", input.action.script.pluginId)\n  const configObjectId = normalizeDenTypeId(\"configObject\", input.action.script.configObjectId)\n  const configObjectVersionId = normalizeDenTypeId(\"configObjectVersion\", input.action.script.configObjectVersionId)\n  const members = await db.select({ role: MemberTable.role }).from(MemberTable).where(and(\n    eq(MemberTable.id, ownerMemberId),\n    eq(MemberTable.organizationId, organizationId),\n    isNull(MemberTable.removedAt),\n  )).limit(1)\n  const member = members[0]\n  if (!member) throw new Error(\"automation_owner_inactive\")\n  if (!memberHasRole(member.role, \"admin\")) {\n    const [teams, configObjectGrants, pluginGrants] = await Promise.all([\n      db.select({ id: TeamMemberTable.teamId }).from(TeamMemberTable)\n        .where(eq(TeamMemberTable.orgMembershipId, ownerMemberId)),\n      db.select({\n        orgMembershipId: ConfigObjectAccessGrantTable.orgMembershipId,\n        orgWide: ConfigObjectAccessGrantTable.orgWide,\n        removedAt: ConfigObjectAccessGrantTable.removedAt,\n        role: ConfigObjectAccessGrantTable.role,\n        teamId: ConfigObjectAccessGrantTable.teamId,\n      }).from(ConfigObjectAccessGrantTable).where(and(\n        eq(ConfigObjectAccessGrantTable.organizationId, organizationId),\n        eq(ConfigObjectAccessGrantTable.configObjectId, configObjectId),\n      )),\n      db.select({\n        orgMembershipId: PluginAccessGrantTable.orgMembershipId,\n        orgWide: PluginAccessGrantTable.orgWide,\n        removedAt: PluginAccessGrantTable.removedAt,","sourceCodeStart":505,"sourceCodeEnd":541,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/workflows.ts#L505-L541","documentation":"Thrown in validateWorkflowAutomationAction when the automation's ownerMemberId does not resolve to an active organization member: the MemberTable lookup by id + organizationId + removedAt IS NULL returns nothing. Automations must be owned by a current, non-removed member with sufficient access.","triggerScenarios":"Creating or updating a workflow automation whose owner member was removed from the organization, never belonged to it, or whose membership row was soft-deleted (removedAt set).","commonSituations":"Offboarding a user while their scheduled automations keep running; transferring ownership to an invalid member id; org data migration leaving dangling member references.","solutions":["Reassign the automation to an active member of the organization (e.g. an admin).","Restore the removed member's membership if the ownership was correct.","Validate ownerMemberId is an active member before calling create/update."],"exampleFix":"// before\nawait createAutomation({ ownerMemberId: departedUserId, ... })\n// after\nawait createAutomation({ ownerMemberId: activeAdminMemberId, ... })","handlingStrategy":"validation","validationCode":"const [m] = await db.select({ role: MemberTable.role }).from(MemberTable)\n  .where(and(eq(MemberTable.id, ownerMemberId), eq(MemberTable.organizationId, organizationId), isNull(MemberTable.removedAt))).limit(1)\nconst ownerActive = !!m","typeGuard":"const isActiveMember = (m: {removedAt: Date | null} | undefined): m is {removedAt: null} => m !== undefined && m.removedAt === null","tryCatchPattern":"try {\n  await updateAutomation({ ownerMemberId, ... })\n} catch (e) {\n  if (e.message === \"automation_owner_inactive\") {\n    // reassign to an active admin member\n  } else throw e\n}","preventionTips":["Reassign automations during offboarding flows.","Validate owner membership (same org, removedAt null) before create/update.","Periodically audit automations for inactive owners."],"tags":["automation","permissions","membership","den-api"],"backgroundTag":"owner-member-inactive","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}