different-ai/openwork · error

workflow_recent_receipt_required

workflow_recent_receipt_required

Error message

workflow_recent_receipt_required

What it means

Saving a workflow requires proof that the exact code being saved has actually run successfully recently in this organization by this member. saveWorkflow queries WorkflowRunTable for a succeeded run with a matching code digest finished within RECENT_RUN_WINDOW_MS; if no such receipt exists it throws 'workflow_recent_receipt_required'. This prevents saving untested or never-executed code as a reusable workflow.

Source

Thrown at ee/apps/den-api/src/workflows.ts:620

    ) {
      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")

  const built = await input.buildTools()
  const manifestByPath = new Map(built.manifest.flatMap((entry) => [
    [entry.scriptPath, entry] as const,
    [entry.scriptPath.replace(/^tools\./, ""), entry] as const,
  ]))
  const requiredCapabilities: Array<{ capabilityName: string; scriptPath: string }> = []
  for (const call of parseCodemodeToolCalls(receipt.tool_calls)) {
    const resolved = manifestByPath.get(call.name)
    if (!resolved) throw new Error(`workflow_capability_unavailable:${call.name}`)
    if (resolved.readOnly !== true) throw new Error(`workflow_requires_read_only_capabilities:${call.name}`)
    if (!requiredCapabilities.some((entry) => entry.scriptPath === resolved.scriptPath)) {
      requiredCapabilities.push({
        capabilityName: resolved.capabilityName,
        scriptPath: resolved.scriptPath,
      })
    }
  }

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Execute the workflow code successfully once before saving, with the same member and organization
  2. Confirm the most recent succeeded run is within the recent-run window; re-run if stale
  3. Make sure the code string is byte-identical to what ran (the digest must match — no whitespace-only edits between run and save)
  4. Check that the run was recorded under the same ownerMemberId, not another membership

Example fix

// before
const result = await runCodemode(code) // run failed
await saveWorkflow({ workflow: { code, ... } }) // throws workflow_recent_receipt_required
// after
const result = await runCodemode(code)
if (!result.ok) throw new Error('fix code and re-run before saving')
await saveWorkflow({ workflow: { code, ... } })
Defensive patterns

Strategy: validation

Validate before calling

async function hasRecentRunReceipt(code: string, organizationId: string, member: string) {
  const rows = await db.select().from(WorkflowRunTable).where(and(
    eq(WorkflowRunTable.organization_id, organizationId),
    eq(WorkflowRunTable.org_membership_id, member),
    eq(WorkflowRunTable.code_digest, codemodeCodeDigest(code)),
    eq(WorkflowRunTable.status, 'succeeded'),
    gt(WorkflowRunTable.finished_at, new Date(Date.now() - RECENT_RUN_WINDOW_MS)),
  )).limit(1)
  return rows.length > 0
}

Type guard

null

Try / catch

try {
  await saveWorkflow(input)
} catch (err) {
  if (err instanceof Error && err.message === 'workflow_recent_receipt_required') {
    // surface 'run the workflow successfully, then save' to the user
  }
}

Prevention

When it happens

Trigger: Calling saveWorkflow with workflow.code whose codemodeCodeDigest has no succeeded WorkflowRun row for the same organization_id, org_membership_id, finished within the recent-run window (e.g. the run failed, ran under a different member/org, or is older than the window).

Common situations: Editing code and saving before re-running it in the UI; the test run happened more than RECENT_RUN_WINDOW_MS ago; the run executed under a different member account; a failed or still-running run is the only record.

Related errors


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