different-ai/openwork · warning

automation_revision_changed

automation_revision_changed

Error message

automation_revision_changed

What it means

DenAutomationRepository.recordSkippedManual locks the automation row FOR UPDATE inside a transaction and verifies that the revision the caller passed still matches the row's current_revision_id. If the automation was edited (or a new revision was published) between the caller reading revisionId and recording the skip, this error aborts the transaction so a stale occurrence is never recorded against a superseded revision.

Source

Thrown at ee/apps/den-api/src/automations/repository.ts:541

    organizationId: string
    ownerMemberId: string
    automation: Automation
    revision: AutomationRevision
    nonce: string
    code: AutomationError["code"]
    message: string
    now: number
  }): Promise<AutomationRun> {
    return db.transaction(async (tx) => {
      const automationId = normalizeAutomationId(input.automation.id)
      const revisionId = normalizeRevisionId(input.revision.id)
      const locked = await tx.select().from(AutomationTable).where(and(
        eq(AutomationTable.id, automationId),
        eq(AutomationTable.organization_id, normalizeOrganizationId(input.organizationId)),
        eq(AutomationTable.owner_member_id, normalizeMemberId(input.ownerMemberId)),
      )).limit(1).for("update")
      if (!locked[0] || locked[0].state === "archived") throw new Error("automation_not_found")
      if (locked[0].current_revision_id !== revisionId) throw new Error("automation_revision_changed")

      const identity = automationOccurrenceIdentity({
        automationId: input.automation.id,
        scheduledFor: null,
        nonce: input.nonce,
      })
      const runId = createDenTypeId("automationRun")
      await tx.insert(AutomationRunTable).values({
        id: runId,
        automation_id: automationId,
        revision_id: revisionId,
        trigger: "manual",
        scheduled_for: null,
        idempotency_key: identity.idempotencyKey,
        status: "skipped",
        execution_target: input.revision.executionTarget ?? "desktop",
        claim_deadline_at: null,
        lease_owner: null,

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Re-fetch the automation's current revision via the repository/API and re-issue recordSkippedManual with the current revisionId
  2. If the occurrence belongs to an old revision intentionally, drop the stale occurrence instead of recording the skip
  3. Use optimistic concurrency on the caller side: capture both automation id and revision id together right before the call

Example fix

// before
await repo.recordSkippedManual({ ...input, revisionId: staleRevisionId })
// after
const current = await repo.automationById(input.automationId)
await repo.recordSkippedManual({ ...input, revisionId: current.currentRevisionId })
Defensive patterns

Strategy: validation

Validate before calling

const current = await repo.automationById(automationId)
if (current.currentRevisionId !== revisionId) {
  throw new Error('stale revision: re-fetch before recordSkippedManual')
}

Type guard

function isCurrentRevision(current: { currentRevisionId: string }, revisionId: string): boolean {
  return current.currentRevisionId === revisionId
}

Try / catch

try {
  await repo.recordSkippedManual(input)
} catch (e) {
  if (String((e as Error)?.message) === 'automation_revision_changed') {
    // refresh revision and retry once, or drop the stale occurrence
  } else throw e
}

Prevention

When it happens

Trigger: Calling recordSkippedManual with a revisionId that no longer equals locked[0].current_revision_id — i.e. the automation was updated/republished after the manual-run occurrence was captured.

Common situations: A user edits the automation while a previously scheduled/manual occurrence is being acknowledged as skipped; a race between an editor publishing a new revision and a worker recording skips for the old revision; retrying an old request after the automation changed.

Related errors


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