{"record":{"id":"757de13b1b51b4dc","repo":"different-ai/openwork","slug":"automation-saved-script-forbidden","errorCode":"automation_saved_script_forbidden","errorMessage":"automation_saved_script_forbidden","messagePattern":"automation_saved_script_forbidden","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-api/src/workflows.ts","lineNumber":552,"sourceCode":"      }).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,\n        role: PluginAccessGrantTable.role,\n        teamId: PluginAccessGrantTable.teamId,\n      }).from(PluginAccessGrantTable).where(and(\n        eq(PluginAccessGrantTable.organizationId, organizationId),\n        eq(PluginAccessGrantTable.pluginId, pluginId),\n      )),\n    ])\n    const grantInput = { memberId: ownerMemberId, teamIds: teams.map((team) => team.id) }\n    if (!resolvePluginArchGrantRole({ ...grantInput, grants: configObjectGrants })\n      && !resolvePluginArchGrantRole({ ...grantInput, grants: pluginGrants })) {\n      throw new Error(\"automation_saved_script_forbidden\")\n    }\n  }\n  const rows = await db.select({ version: ConfigObjectVersionTable })\n    .from(ConfigObjectVersionTable)\n    .innerJoin(ConfigObjectTable, and(\n      eq(ConfigObjectTable.id, ConfigObjectVersionTable.configObjectId),\n      eq(ConfigObjectTable.organizationId, organizationId),\n      eq(ConfigObjectTable.objectType, \"workflow\"),\n      eq(ConfigObjectTable.status, \"active\"),\n      isNull(ConfigObjectTable.deletedAt),\n    ))\n    .innerJoin(PluginConfigObjectTable, and(\n      eq(PluginConfigObjectTable.configObjectId, ConfigObjectTable.id),\n      eq(PluginConfigObjectTable.pluginId, pluginId),\n      isNull(PluginConfigObjectTable.removedAt),\n    ))\n    .where(and(\n      eq(ConfigObjectVersionTable.id, configObjectVersionId),","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/workflows.ts#L534-L570","documentation":"Thrown in validateWorkflowAutomationAction when the automation's owner member is not an admin and holds no access grant — via direct membership grants or team grants — for either the referenced config object (saved script) or the referenced plugin, per resolvePluginArchGrantRole. Only owners with at least one such grant may automate the saved script.","triggerScenarios":"Creating/updating an automation whose ownerMemberId lacks both ConfigObjectAccessGrantTable and PluginAccessGrantTable coverage (directly or via TeamMemberTable teams) for the script's config object / plugin.","commonSituations":"Automation reassigned to a member without plugin access; team membership changed removing the needed team grant; a grant revoked while the automation edit was pending.","solutions":["Grant the owner member (or one of their teams) an access grant on the config object or plugin.","Promote the owner to an org admin role, which bypasses the grant check.","Choose a different owner who already has access to the saved script/plugin."],"exampleFix":"// before\nawait createAutomation({ ownerMemberId: viewerId, configObjectId, pluginId })\n// after\nawait db.insert(ConfigObjectAccessGrantTable).values({ orgMembershipId: viewerId, configObjectId, role: \"editor\" })\nawait createAutomation({ ownerMemberId: viewerId, configObjectId, pluginId })","handlingStrategy":"validation","validationCode":"const isOwnerGranted = resolvePluginArchGrantRole({ memberId: ownerMemberId, teamIds, grants: configObjectGrants }) !== null\n  || resolvePluginArchGrantRole({ memberId: ownerMemberId, teamIds, grants: pluginGrants }) !== null\nif (!isAdmin && !isOwnerGranted) throw new Error(\"would fail: automation_saved_script_forbidden\")","typeGuard":null,"tryCatchPattern":"try {\n  await createAutomation(input)\n} catch (e) {\n  if (e.message === \"automation_saved_script_forbidden\") {\n    // add a ConfigObject/Plugin access grant for the owner or pick an admin owner\n  } else throw e\n}","preventionTips":["Check owner grants (direct + team) before saving automations.","Avoid revoking grants while dependent automations exist.","Prefer admin owners for org-wide automations."],"tags":["automation","permissions","access-grant","den-api"],"backgroundTag":"insufficient-access-grant","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}