n8nautomationapi

n8n execution crashed, startedAt null? It's a queue mode race

··10 min read
n8n execution crashed, startedAt null? It's a queue mode race

Your executions list shows crashed. The execution has no start time, no node ever ran, and the workflow logs are empty. If you took n8n 2.45.0 when it shipped on October 20, 2026, that isn't your workflow failing. It's a race in queue mode that n8n patched the next day.

Quick answer: An n8n execution marked crashed with startedAt = null in queue mode is a bug in n8n 2.45.0, fixed in 2.45.1 (released October 21, 2026). An idle worker claimed a Redis queue job and its lock in two separate steps, so a worker whose event loop was blocked could hold an active job with no lock. n8n's stall sweep then failed that job immediately, because n8n sets maxStalledCount to 0 and no longer retries stalled jobs. Pin your Docker image to n8nio/n8n:2.45.1 or later and recreate the container. If a video step is what blocks your event loop (FFmpeg in Execute Command, a Code node on a video buffer), move it to an HTTP submit-and-poll call against a media API like FFmpeg Micro so no long synchronous work runs inside n8n at all.

Why the execution says crashed but has no start time

The conventional read is that crashed means the process died mid-run: OOM kill, container restart, worker eviction. That's usually right, and it's why most troubleshooting guides send you to docker logs and memory limits. But startedAt = null rules all of that out. The execution never began.

The mechanism is in n8n PR #41525. An idle Bull worker waits for work with a blocking Redis BRPOPLPUSH from wait to active. Redis moves the job to active the instant it's available, and the worker sets the job's lock in a later call. Between those two operations, the job is active and unlocked. If the worker's event loop is busy in that window, the lock never gets set, the stall check sweeps, finds an active job with no lock, and fails it. Because n8n sets maxStalledCount to 0, there's no retry. The row lands as crashed with a null startedAt.

The fix inverts the order: the idle worker waits for a job without taking it, then takes the job and its lock in one Redis script. A worker with a blocked event loop holds nothing, and another worker picks the job up.

How to tell this apart from an OOM kill or a dead worker

Three signals separate the 2.45.0 race from an actual worker death.

  • startedAt is null and no node has any run data. A worker that died mid-execution leaves a start time and partial node output.
  • The worker container is still up, with no restart and no OOMKilled in docker inspect. The process survived; only the job was lost.
  • It's intermittent and tracks your long-running workflows, not memory pressure. The race needs a busy event loop, so it hits when something else is chewing on a file.

An OOM-killed worker shows the opposite shape: a start time, some completed nodes, and exit code 137 on the container.

Which version to run, and how to make the upgrade apply

2.45.0 shipped on October 20, 2026 and carries the race. n8n 2.45.1 landed the next day with the core fix "Claim an idle worker's next queue job and its lock in one step (#41558)". PR #41558 is the backport of #41525 onto the 2.45.x release branch. 2.45.2 and 2.45.3 followed on October 22 and 23. 2.45.1 is the floor, with no reason to stop there.

Pin the tag explicitly rather than trusting latest:

services:
  n8n:
    image: n8nio/n8n:2.45.3
  n8n-worker:
    image: n8nio/n8n:2.45.3
    command: worker

Then recreate, not just pull:

docker compose pull
docker compose up -d --force-recreate n8n n8n-worker
docker compose exec n8n n8n --version

A pull that doesn't recreate the container leaves you running the old image, the most common reason an n8n patch appears not to have worked. We covered that trap in docker compose pull won't apply the n8n security update patch.

To prove the fix landed, run one execution that occupies a worker for several minutes, then submit a second while the first is mid-flight. On 2.45.0 the second comes back crashed with no start time. On 2.45.1+ it queues and runs. Lost executions don't re-run themselves, so replay them from the executions list by hand.

No env var fixes this

QUEUE_WORKER_MAX_STALLED_COUNT is the knob community threads keep pointing at, and it does nothing. n8n removed it in 2.0 and no longer auto-retries stalled jobs. One widely-read thread, queue mode reliability much worse after upgrading to v2.x, has self-hosters reporting failure rates climbing from roughly 1-2% on 1.x to 5-20% on 2.x and blaming that removal. The missing retry is real, but it's the reason the race is fatal, not the reason it happens.

The lease settings in n8n's queue mode environment variables explain why a blocking node is dangerous here:

SettingDefaultWhat it means
`QUEUE_WORKER_LOCK_DURATION`60000 msA job's lock expires after 60 seconds
`QUEUE_WORKER_LOCK_RENEW_TIME`10000 msThe worker must renew every 10 seconds
`QUEUE_WORKER_STALLED_INTERVAL`30000 msThe stall sweep runs every 30 seconds

Renewing a lease every 10 seconds requires the event loop to be free every 10 seconds. A node that pegs it for four minutes misses 24 renewals. Raising QUEUE_WORKER_LOCK_DURATION to 600000 buys ten minutes of headroom and moves the failure instead of removing it: the next job that blocks for eleven minutes fails the same way, and genuine worker deaths now take ten minutes to detect.

What in your workflow blocks the event loop for minutes

The race needs a worker that can't answer Redis for a while, and in content-automation pipelines that's almost always the video step. Node.js runs your workflow on one thread, so anything synchronous and long starves everything else on that worker, including lock renewal. The usual suspects:

  • FFmpeg through the Execute Command node. n8n disabled this node by default in 2.0, and a 1080p transcode holds the worker for minutes.
  • A Code node operating on a video buffer. Base64-encoding or slicing a few hundred megabytes in JavaScript is synchronous CPU work on the main thread.
  • Read/Write Files from Disk on a large MP4. A 1 GB read is the classic n8n memory-and-blocking failure, and it's distinct from a timeout.

Upgrading to 2.45.1 stops the lost-job symptom. It doesn't make those steps safe. A worker pinned at 100% CPU for four minutes still isn't processing anything else, and its memory ceiling is still your largest input file. The durable fix is that the bytes never enter the n8n process.

Make the video step an HTTP submit, poll, download

A media API turns a four-minute blocking node into three short HTTP requests. n8n holds a URL and a job ID, never the file, so the event loop stays free while the encode runs. With FFmpeg Micro, the shape is the same whether you call it from an HTTP Request node, Make, Zapier, or your own code.

Submit the job:

curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
  -H "Authorization: Bearer $FFMPEG_MICRO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [{ "url": "gs://your-bucket/1234567890-video.mp4" }],
    "outputFormat": "mp4",
    "preset": { "quality": "medium", "resolution": "1080p" }
  }'

You get back a job id and "status": "pending". Poll it:

curl https://api.ffmpeg-micro.com/v1/transcodes/abc123-job-uuid \
  -H "Authorization: Bearer $FFMPEG_MICRO_KEY"

While it runs you see "status": "processing"; when it's done you get "status": "completed" with a completedAt. Then ask for a signed download URL:

curl https://api.ffmpeg-micro.com/v1/transcodes/abc123-job-uuid/download \
  -H "Authorization: Bearer $FFMPEG_MICRO_KEY"

In n8n that's an HTTP Request node, a Wait node of 5 to 10 seconds, an IF node checking status, and a loop back to the status check. Each poll returns in milliseconds, so the worker renews its Redis lock on schedule the whole time. Polling costs nothing: checking job status, listing jobs, and downloading outputs are all free on FFmpeg Micro, and billing is one token per 10 seconds of input video, metered per second. Failed jobs are never billed. A 45-second clip costs 4.5 tokens whether the encode takes eight seconds or eighty.

The full node-by-node rebuild is in n8n 3.0 breaking changes kill your FFmpeg step. Send it HTTP. If you're still keeping a binary inside the image, Why n8n says "No usable ffmpeg was found" covers why that breaks on upgrade.

Manual FFmpeg node vs. submit-and-poll, on a queue-mode worker

The difference that matters isn't encode speed. It's how long the worker can't talk to Redis.

FFmpeg in Execute Command / Code nodeHTTP submit and poll
Event loop blockedMinutes, for the whole encodeMilliseconds per request
Lock renewals missedMany (renewal is every 10s)None
Worker memoryScales with input file sizeFlat, a URL and a job ID
Needs FFmpeg in the imageYes, rebuild on every n8n patchNo
Works on n8n CloudNoYes
Cost modelYour server's uptimePer second of input video

Pitfalls that bite after the upgrade

  1. Only the main instance got the new tag. Workers run the same image and need the same pin, or the fixed claim logic isn't where the jobs are.
  2. The lock duration was raised during debugging and left there. Put QUEUE_WORKER_LOCK_DURATION back to the 60000 default once you're on 2.45.1+, or real worker deaths go undetected that long.
  3. Crashed executions were assumed to retry. They don't. With maxStalledCount at 0, anything that failed on 2.45.0 has to be replayed from the executions list.
  4. The Wait node is set to 1 second. Polling is free, but a one-second loop on a four-minute job makes 240 HTTP requests and clutters the execution. Five to ten seconds is better.

One more specific to this release: 2.45.0 made the durable scheduler the default, so "every N minutes" schedules count N from publish time, not from clock boundaries. A nightly render that looks like it moved after the upgrade is that change, not this bug.

FAQ

Does n8n 2.45.1 fix the crashed-with-null-startedAt bug, or do I need 2.45.3?

n8n 2.45.1 contains the fix, shipped October 21, 2026 as "Claim an idle worker's next queue job and its lock in one step (#41558)". 2.45.2 and 2.45.3 followed on October 22 and 23 with further patches, so go straight to the newest 2.45.x.

Can I set QUEUE_WORKER_MAX_STALLED_COUNT to work around it without upgrading?

No. n8n removed QUEUE_WORKER_MAX_STALLED_COUNT in version 2.0, and setting it on any 2.x build has no effect. There's no env-var workaround for the two-step claim race; the only remedy is running 2.45.1 or later.

Will the crashed executions re-run on their own?

Crashed executions from this bug don't re-run automatically. n8n sets maxStalledCount to 0, so a stalled job is failed rather than retried. Replay them by hand from the executions list after the upgrade.

Is this the same thing as executions stuck in "Queued" or "Running"?

Executions stuck in Queued are the opposite failure: no worker ever claimed the job, which usually points at Redis connectivity or a worker that isn't running. This bug is a worker that did claim the job and then lost it, so the status ends up crashed.

If you'd rather have a working API key and a finished transcode in the same sitting than keep an encoder inside your automation host, the quickstart runs the whole flow: it creates a temporary key, then does the presigned upload, the transcode, the poll, and the download, showing the request and response at each step. The free tier gives you 200 tokens, about 33 minutes of video, with no card.

About Javid Jamae

Founder & CEO at FFmpeg Micro

Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.

Software EngineeringVideo ProcessingFFmpegCloud ArchitectureAPI DesignAutomation

Ready to process videos at scale?

Start using FFmpeg Micro's simple API today. No infrastructure required.

Get Started Free