different-ai/openwork · error
saved_workflow_plugin_context_required
saved_workflow_plugin_context_required
Error message
saved_workflow_plugin_context_required
What it means
saveWorkflow in the Den API enforces that when a workflow is saved under an explicit pluginId, the caller must supply a PluginArchActorContext whose organization and current member exactly match the organizationId and ownerMemberId arguments. The library throws 'saved_workflow_plugin_context_required' when input.context is missing or its organization/member identity diverges, because plugin-level authorization (requirePluginArchResourceRole with role 'editor') cannot be performed without a matching actor context.
Source
Thrown at ee/apps/den-api/src/workflows.ts:603
export async function saveWorkflow(input: {
organizationId: string
ownerMemberId: string
workflow: SaveWorkflowInput
buildTools: () => Promise<BuiltCodemodeTools>
context?: PluginArchActorContext
}): Promise<{ pluginId: string; configObjectId: string; configObjectVersionId: string }> {
const organizationId = normalizeDenTypeId("organization", input.organizationId)
const ownerMemberId = normalizeDenTypeId("member", input.ownerMemberId)
const requestedPluginId = input.workflow.pluginId
? normalizeDenTypeId("plugin", input.workflow.pluginId)
: null
if (requestedPluginId) {
if (
!input.context
|| input.context.organizationContext.organization.id !== organizationId
|| input.context.organizationContext.currentMember.id !== ownerMemberId
) {
throw new Error("saved_workflow_plugin_context_required")
}
await requirePluginArchResourceRole({
context: input.context,
resourceId: requestedPluginId,
resourceKind: "plugin",
role: "editor",
})
}
const receipts = await db.select().from(WorkflowRunTable).where(and(
eq(WorkflowRunTable.organization_id, organizationId),
eq(WorkflowRunTable.org_membership_id, ownerMemberId),
eq(WorkflowRunTable.code_digest, codemodeCodeDigest(input.workflow.code)),
eq(WorkflowRunTable.status, "succeeded"),
gt(WorkflowRunTable.finished_at, new Date(Date.now() - RECENT_RUN_WINDOW_MS)),
)).orderBy(desc(WorkflowRunTable.finished_at)).limit(1)
const receipt = receipts[0]
if (!receipt) throw new Error("workflow_recent_receipt_required")
View on GitHub (pinned to 2b7df46e8a)
Solutions
- Always pass a PluginArchActorContext when workflow.pluginId is provided
- Ensure input.context.organizationContext.organization.id equals the organizationId argument
- Ensure input.context.organizationContext.currentMember.id equals the ownerMemberId argument
- If saving to the member's default workflows plugin, omit workflow.pluginId so no context is required
Example fix
// before
await saveWorkflow({ organizationId, ownerMemberId, workflow: { pluginId: somePluginId, ... }, buildTools })
// after
await saveWorkflow({ organizationId, ownerMemberId, workflow: { pluginId: somePluginId, ... }, buildTools, context: actorContext // must match organizationId & ownerMemberId
}) Defensive patterns
Strategy: validation
Validate before calling
function canSaveToPlugin(input) {
return !input.workflow.pluginId || Boolean(
input.context
&& input.context.organizationContext.organization.id === input.organizationId
&& input.context.organizationContext.currentMember.id === input.ownerMemberId
)
} Type guard
function hasMatchingActorContext(input: Parameters<typeof saveWorkflow>[0]): input is typeof input & { context: PluginArchActorContext } {
return input.context != null
&& input.context.organizationContext.organization.id === input.organizationId
&& input.context.organizationContext.currentMember.id === input.ownerMemberId
} Try / catch
try {
await saveWorkflow(input)
} catch (err) {
if (err instanceof Error && err.message === 'saved_workflow_plugin_context_required') {
throw new Error('Provide an actor context matching organizationId/ownerMemberId when pluginId is set')
}
throw err
} Prevention
- Never set workflow.pluginId without also supplying input.context
- Assert context identity (org + member) equals the save target in a pre-flight check
- Centralize saveWorkflow calls in one helper that always loads a fresh actor context
- Write a test asserting the no-context + pluginId combination fails fast
When it happens
Trigger: Calling saveWorkflow with workflow.pluginId set while (a) input.context is undefined, (b) input.context.organizationContext.organization.id differs from input.organizationId, or (c) input.context.organizationContext.currentMember.id differs from input.ownerMemberId.
Common situations: Server-side/cron callers saving workflows on behalf of a member without loading the actor context; passing a context from a different organization after an org switch; reusing a stale member id after the owner membership changed; internal scripts that omit context for the fast path but also set a pluginId.
Related errors
- saved_workflow_manager_context_required
- workflow_recent_receipt_required
- saved_workflow_plugin_not_found
- invalid_mcp_connection_payload
- invalid_marketplace_payload
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/273412279ca2d9a7.
Report an issue: GitHub.