n8nffmpegautomation

n8n 3.0 breaking changes: fix your video step in this order

··10 min read
n8n 3.0 breaking changes: fix your video step in this order

You upgraded, and the video step that worked on Friday now dies at the one-minute mark. Or it never starts, because the npm install you had FFmpeg bolted onto isn't a supported deployment anymore. Four changes in n8n 3.0 land on media work specifically, and they have very different blast radii.

Quick answer: The n8n 3.0 breaking changes that break a video workflow are four: N8N_RUNNERS_TASK_TIMEOUT defaulting down from 300 seconds to 60, self-hosted n8n becoming Docker-only with no runnable npm package, the Compression node's caps falling to 256 MiB and 1,000 zip entries, and 30+ removed nodes including Function, Read PDF, and Read/Write Binary File. Open Settings > Migration Report first, then set N8N_RUNNERS_TASK_TIMEOUT explicitly on both the n8n container and the task-runner container, and rebuild your custom FFmpeg image for a Docker deployment. If you'd rather stop sizing a timeout against video length, submit the encode to FFmpeg Micro as one HTTP Request node and poll the job, where no single request is long enough for any timeout to matter.

Open Settings > Migration Report before you change a single env var

The Migration Report tells you which of your workflows actually broke instead of making you guess from a changelog. n8n's v3.0 breaking changes page points you at it: it splits findings into Workflow issues and Instance issues, sorts them by impact, and needs global admin access to open. Read it before editing docker-compose.yml. Half the items on the official list won't apply to your instance, and one probably explains your failure in a line.

The report won't rank those items by how much video work they kill. That order is below.

The four n8n 3.0 breaking changes that hit video work

Every item on n8n's full list is real, but a hand-rolled FFmpeg pipeline only touches four. Fix them in this order.

1. The task-runner timeout dropped from 300 seconds to 60

In n8n 3.0 the default value of N8N_RUNNERS_TASK_TIMEOUT is 60 seconds, down from 300. Any Code node that shells out to FFmpeg and waits now gets aborted after a minute, which is shorter than most real encodes.

The part the upgrade checklists skip: per n8n's task-runner environment variables, the launcher passes its timeout down to each runner and the runner aborts at its own value. Set it on the broker only and you still get killed at 60. It goes on both containers:

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n:3.0
    environment:
      - N8N_RUNNERS_ENABLED=true
      - N8N_RUNNERS_MODE=external
      - N8N_RUNNERS_TASK_TIMEOUT=300
  runners:
    image: n8nio/runners:3.0   # tag must match the n8n image
    environment:
      - N8N_RUNNERS_TASK_TIMEOUT=300
      - NODE_FUNCTION_ALLOW_BUILTIN=child_process

In external runner mode the Code node executes inside the n8nio/runners container, not the n8n one, so FFmpeg has to be installed in that image. And a Code node that spawns a binary needs child_process allowed through NODE_FUNCTION_ALLOW_BUILTIN, which is not on by default. Community FFmpeg-enabled builds of the runners image exist, like maksimkurb/n8n-ffmpeg, if you want the binary in-instance without maintaining the Dockerfile yourself.

2. Docker-only self-hosting killed the npm install you added FFmpeg to

Self-hosted n8n 3.0 requires a Docker-based deployment. npm install n8n and npx n8n are gone, and no runnable n8n package is published to npm. If your video step worked because ffmpeg was on the host PATH and the Execute Command node could reach it, that whole arrangement is now unsupported.

Moving into Docker doesn't restore it either. The official image has been distroless since mid-2026, so the USER root; RUN apk add --no-cache ffmpeg recipe from older tutorials fails: there's no apk inside to run. The working pattern is a multi-stage build that copies a static FFmpeg in from a build stage, plus fontconfig and a font package like ttf-dejavu if you use drawtext or burn in subtitles. That image then needs re-verifying on every n8n release, which is the same tax described in n8n CVE October 2026: upgrade without breaking FFmpeg.

3. The Compression node caps at 256 MiB and 1,000 entries

The Compression node's decompression limit fell from 2 GiB to 256 MiB and its zip-entry limit from 5,000 to 1,000. This matters to video work only if you unzip asset bundles inside the workflow, which plenty of UGC and stock-footage pipelines do. Raw video moving through other nodes isn't affected.

Restore the old numbers with N8N_COMPRESSION_NODE_MAX_DECOMPRESSED_SIZE_BYTES=2147483648 and N8N_COMPRESSION_NODE_MAX_ZIP_ENTRIES=5000.

4. The removed nodes older video templates still contain

Version 3.0 removes more than 30 nodes, per n8n's deprecated and versioned nodes page. Most have a direct replacement: Function and Function Item become Code, Cron and Interval become the Schedule Trigger, Read PDF becomes Extract From File, the legacy OpenAI node becomes the current one. $evaluateExpression() is also gone from the Code node.

Read Binary File, Read Binary Files, and Write Binary File are removed with no in-n8n equivalent for the job they did, which was shuttling a video to a path on disk, running FFmpeg over it, and reading the output back as binary. That read/write pair plus Execute Command was the self-hosted FFmpeg pattern. There's no node swap that rebuilds it. Also check N8N_UNVERIFIED_PACKAGES_ENABLED, which flips from true to false in 3.0: already-installed unverified community nodes stop loading after the upgrade, so a third-party FFmpeg node can vanish from your workflow with no error you'd connect to the upgrade.

Why raising N8N_RUNNERS_TASK_TIMEOUT doesn't actually fix encoding

Every upgrade guide treats 60 seconds as a number to raise, and for a slow API call or a heavy data transform, it is. Encoding is different: an FFmpeg run's duration is a function of input length and filter cost, so there's no value of N8N_RUNNERS_TASK_TIMEOUT that's safe for arbitrary inputs. Set it to 300 and a 12-minute podcast still blows through it. Set it to 3600 and you're holding a runner slot for an hour while other executions queue behind it, with the whole decoded working set in that container's memory.

The advice to "split the long Code step into batches" doesn't apply either. One ffmpeg -i in.mp4 … out.mp4 is one process that runs until it's done.

n8n didn't shrink that budget arbitrarily. Long synchronous work in a shared task runner was always the wrong shape, and 3.0 just stopped pretending otherwise. Which means the real fix isn't a bigger timeout. It's not running the encoder inside n8n at all.

The same transcode as three HTTP Request nodes

An async job API changes what each n8n node has to survive. You submit, poll, and download, and the longest single HTTP call is a status check that returns in milliseconds. The HTTP Request node's own timeout is separate from the runner timeout and isn't overridden by EXECUTIONS_TIMEOUT, so with this pattern there's nothing left to tune.

After upgrading to 3.0FFmpeg in a Code node or runnerAsync job API over HTTP Request
Longest single operationthe full encode, bounded by `N8N_RUNNERS_TASK_TIMEOUT`a status poll, well under a second
Where FFmpeg livesyour `n8nio/runners` image, rebuilt each releasenowhere in your stack
Needs `child_process` allowedyesno
Survives the unverified-packages fliponly if no community node is involvedyes, HTTP Request is a core node
Memory during the jobdecode buffers in the runner containernone in n8n

With FFmpeg Micro, those three nodes are a presigned upload, a job submit, and a poll loop on a Wait node. The submit is a POST to /v1/transcodes:

{
  "inputs": [{ "url": "gs://<YOUR_BUCKET>/1234567890-video.mp4" }],
  "outputFormat": "mp4",
  "preset": { "quality": "medium", "resolution": "1080p" }
}

It comes back immediately with a job id and "status": "pending". You poll GET /v1/transcodes/{id} until completed, then GET /v1/transcodes/{id}/download for a signed URL. Captions follow the same shape through POST /v1/transcribe, which returns an SRT you can feed straight into a subtitles='…' filter on a later transcode job. Billing is per second of input video, not per second of our server time, and failed jobs aren't billed, so a 30-second trim out of a one-hour recording costs 30 seconds.

The honest caveat: FFmpeg Micro publishes an n8n community node too, and a community node is exactly the category 3.0 now gates behind N8N_UNVERIFIED_PACKAGES_ENABLED. Plain HTTP Request nodes don't have that problem, which is why we document that path first.

Common pitfalls after the 3.0 upgrade

Five mistakes after a 3.0 upgrade waste an afternoon before you spot them.

  • Confusing two different 60-second errors. "Task request timed out after 60 seconds" is a long-standing failure governed by N8N_RUNNERS_TASK_REQUEST_TIMEOUT, raised when no runner is available or the runner is at capacity. If the message says request timed out, you have a runner availability problem, not an encode-length problem.
  • Setting the timeout on the wrong container. Broker at 300, runners at the default, still dead at 60.
  • Assuming you're on 3.0. Check your actual tag. The breaking-changes doc went present tense on October 7, 2026, but the 2.x line kept shipping patches after that, and a lot of "3.0 broke my workflow" reports turn out to be 2.4x instances.
  • Forgetting fonts in a rebuilt image. No fontconfig, no drawtext, no subtitle burn-in, and no error that says so. If FFmpeg isn't resolving at all, why n8n says "No usable ffmpeg was found" covers the resolution order.
  • Leaving big files routed through n8n. Even with every timeout raised, pulling a 1 GB file into a node is how self-hosted instances fall over. Pass URLs between steps and let the processor fetch the bytes.

FAQ

I set N8N_RUNNERS_TASK_TIMEOUT=300 and still get killed at 60 seconds. Which container needs it?

Both containers need it. The task-runner launcher passes its timeout down to each runner, and the runner aborts at its own configured value, so an n8n container set to 300 with runner containers on the 60-second default caps every task at 60.

In external runner mode, does FFmpeg go in the n8n image or the runners image?

FFmpeg has to be installed in the n8nio/runners image, because that's where the Code node actually executes in external mode. Its version also has to match your n8n image version, so both get rebuilt and re-pinned together on every upgrade.

Does the 256 MiB Compression cap affect video files?

The Compression node's 256 MiB cap applies to decompressing archives, not to video files moving through other nodes. It bites video pipelines that unzip asset bundles, and you can restore the old 2 GiB limit with N8N_COMPRESSION_NODE_MAX_DECOMPRESSED_SIZE_BYTES=2147483648.

What replaces the removed Read Binary File and Write Binary File nodes?

Nothing inside n8n replaces Read Binary File and Write Binary File for the local-disk round trip a video pipeline used them for. Workflows that wrote a file, ran Execute Command over it, and read the result back have to move the file handling out of n8n entirely.

If I raise every timeout, can I just keep encoding inside n8n?

You can, for short and predictable inputs. A four-minute encode in-process still holds a runner slot for its whole duration and keeps its working set in that container's memory, so one unusually long upload can stall unrelated executions. If your inputs vary in length, the timeout is the wrong lever. Our earlier write-up on what to change in your FFmpeg step for 3.0 goes through the node-by-node rewrite.

If you want the submit-poll-download pattern working before deciding whether to keep maintaining a runners image, the quickstart runs it for you: it creates a temporary API key and walks the presigned upload, transcode, poll, and download with the real request and response at each step. Signing up is free and needs no card, and the 200 tokens you get cover about 33 minutes of video.

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