opsira

n8n workflow edits that silently never run

In short

Updating the workflow row in the database changes the draft, not the copy that executes. The edit reads back perfectly and never runs.

We made five changes to four workflows by writing directly to Postgres. All five applied cleanly. All five read back correctly. None of them ran.

We only caught it because one change added a new action to an internal API, and calling it returned unknown action. The other four were behaviour changes to email and alerting, and they had been quietly doing nothing for a day.

Why it happens

There are two copies of every workflow. workflow_entity holds the draft, which is what the editor loads. workflow_history holds the executable copy, one row per version. Which history row actually runs is decided by activeVersionId on the workflow row.

So an UPDATE to the draft edits something that never executes. Restarting does not help, because the restart reloads the same unchanged executable copy. Saving in the editor works because the UI performs the whole publish sequence for you.

How to tell

SELECT w.id, w."activeVersionId",
       (w.nodes::text = h.nodes::text) AS draft_matches_executable
FROM workflow_entity w
LEFT JOIN workflow_history h
  ON h."workflowId" = w.id AND h."versionId" = w."activeVersionId"
WHERE w.active = true;

Any row returning false is a workflow whose editor view is lying to you.

The fix

  1. Update the draft.
  2. Insert a new history row with a fresh version uuid, same nodes and connections.
  3. Point versionId and activeVersionId at it and bump the version counter.
  4. Restart.

If a workflow has exactly one history row and its version already equals activeVersionId, you can update both copies in one transaction and skip minting a version. Check those two conditions first, because with multiple history rows you will edit one that is not active and be back where you started.

Simplest option

If you can reach the editor, make the change there. Saving in the UI publishes correctly by definition. All of this only matters when scripting changes or working on an instance you cannot open in a browser.

How not to verify

Never confirm a workflow edit by reading back the column you just wrote. It shows your new code whether or not it is live, and the editor agrees with it. Compare against the active history row, or test the behaviour.

Observed on n8n 2.29.9 with a Postgres backend. The table layout has changed across versions, so check your own schema before assuming these column names match.

Need help with any of this?

These notes are free and always will be. If you would rather someone just set it up, or you are stuck on something similar, get in touch at hello@opsira.io.