XBSTACK XBSTACK
Xiaobai

Xiaobai

Developer · Builder

Building AI engineering systems, developer tools and long-term digital assets at XBSTACK.

About Xiaobai & XBSTACK →
n8n 2.35.3 $json.data.sort() returning null compared with the normal 2.34.5 array result

n8n 2.35.3 $json Array Methods Return null: Reproduction and Workaround

In n8n 2.35.3 Edit Fields, $json.data.sort(), splice(), fill() and copyWithin() return null. Compare official 2.34.5 vs 2.35.3 Docker runs and tested copy-first workarounds.

Published · 2026-08-195 min readXBSTACK
#n8n#Edit Fields#Expressions#Array#Regression#Debugging#Workflow

If you upgraded to n8n 2.35.3 and an Edit Fields expression such as:

{{ $json.data.sort() }}

suddenly evaluates to:

null

do not start by rewriting the input JSON. I reproduced the behavior locally with the official n8nio/n8n:2.34.5 and n8nio/n8n:2.35.3 Docker images. The same isolated expressions work on 2.34.5 and fail with null on 2.35.3.

The regression is broader than sort() in this test:

{{ $json.data.sort() }}
{{ $json.data.splice(0, 2) }}
{{ $json.data.fill("X", 0, 2) }}
{{ $json.data.copyWithin(0, 2, 4) }}

All four returned null on 2.35.3. reverse() still worked. Copying the array first also worked.

Do not mutate $json.data directly
Copy first, then mutate the copy

The shortest production containment I verified is:

{{ [...$json.data].sort() }}

I also tested copy-first splice(), fill() and copyWithin() on 2.35.3 rather than assuming they would behave like sort().

n8n 2.35.3 production troubleshooting and upgrade guide: confirm the version, isolate the repro, identify affected methods, apply copy-first mitigation and evaluate rollback

Why this is a version regression, not just a bad expression

n8n issue #36540, opened on August 18, 2026, reports that several mutating Array methods called directly on $json arrays started evaluating to null after an upgrade from 2.34.5 to 2.35.3. The report names the same four affected methods and also notes that reverse() and copy-first sorting still work.

I did not treat the issue report itself as enough evidence. I pulled both official Docker images and executed the same Edit Fields expressions with the same input on both versions.

The comparison environment was:

ItemControlRegression
n8n2.34.52.35.3
Docker imagen8nio/n8n:2.34.5n8nio/n8n:2.35.3
Node.jsv24.18.0v24.18.1
Databasedefault SQLitedefault SQLite
Executionn8n CLI executen8n CLI execute
Edit Fieldssame node shapesame node shape

Every method was given its own independent branch with this input:

{
  "data": [
    "Mango",
    "Apple",
    "Kiwi",
    "Orange",
    "Blueberry",
    "Banana",
    "Peach",
    "Grape",
    "Pineapple",
    "Strawberry"
  ]
}

That isolation matters. My first combined-field workflow put several mutating expressions in one Edit Fields node. On 2.34.5 those methods really mutate the shared input array, so one field can change what a later field sees. The isolated workflow removes that source of noise and is the authoritative version matrix.

2.34.5 versus 2.35.3

The isolated results:

n8n 2.34.5 versus 2.35.3 Array regression matrix: sort, splice, fill and copyWithin return null on 2.35.3 while reverse remains normal

Expressionn8n 2.34.5n8n 2.35.3
$json.data.sort()sorted arraynull
$json.data.splice(0, 2)['Mango','Apple']null
$json.data.fill('X', 0, 2)filled arraynull
$json.data.copyWithin(0, 2, 4)mutated arraynull
$json.data.reverse()worksworks
[...$json.data].sort()worksworks
$json.data.slice().sort()worksworks

Three details narrow the failure surface:

  1. The input and node shape are unchanged; only the n8n version changes.
  2. Not every mutating method is affected; reverse() works on 2.35.3.
  3. Sorting itself still works when it is performed on a copied array.

So the observable boundary is not “JavaScript arrays are broken.” It is that some mutating methods called directly on arrays exposed by $json are handled differently in 2.35.3.

I am deliberately stopping there on root cause. Until upstream maintainers publish a fix or a concrete internal change, it would be speculation to claim that a particular proxy, immutability guard, expression sandbox or serialization path is the cause.

Tested workaround: copy first, then mutate

For a production workflow, I prefer the smallest reversible change first.

n8n 2.35.3 temporary fix: avoid mutating $json.data directly, copy the array first, then call sort, splice, fill or copyWithin

sort()

Before:

{{ $json.data.sort() }}

Use:

{{ [...$json.data].sort() }}

or:

{{ $json.data.slice().sort() }}

Both passed on 2.35.3.

splice()

Before:

{{ $json.data.splice(0, 2) }}

Use:

{{ [...$json.data].splice(0, 2) }}

My 2.35.3 run returned:

["Mango", "Apple"]

Remember that JavaScript splice() returns the removed elements. If your business logic needs the remaining array, changing only the regression workaround does not change that JavaScript semantic.

fill()

Before:

{{ $json.data.fill("X", 0, 2) }}

Use:

{{ [...$json.data].fill("X", 0, 2) }}

Verified 2.35.3 output:

["X", "X", "Kiwi", "Orange", "Blueberry", "Banana", "Peach", "Grape", "Pineapple", "Strawberry"]

copyWithin()

Before:

{{ $json.data.copyWithin(0, 2, 4) }}

Use:

{{ [...$json.data].copyWithin(0, 2, 4) }}

Verified 2.35.3 output:

["Kiwi", "Orange", "Kiwi", "Orange", "Blueberry", "Banana", "Peach", "Grape", "Pineapple", "Strawberry"]

These are runtime results from the same official 2.35.3 image, not untested equivalents inferred from the sort() workaround.

Why copy-first is a better expression boundary anyway

n8n expressions reference data produced by previous nodes. Calling sort(), splice(), fill() or copyWithin() directly on $json.data mixes two concerns: reading the current input and mutating the object that exposes that input.

That can make workflows harder to reason about even without this regression. The combined-field control on 2.34.5 demonstrated the risk directly: one mutating field can change the array that later expressions read.

Copy-first expressions separate the requested result from the input object:

{{ [...$json.data].sort() }}

For a simple string array, that boundary is clear. For arrays of nested objects, remember that spread syntax performs a shallow copy, so deeper mutation still requires its own design decision.

Should you downgrade to 2.34.5?

A rollback is not automatically the safest first move.

If only a handful of Edit Fields expressions are affected, replacing direct mutation with copy-first expressions is usually a smaller and more reversible production change. Search your workflows for calls such as:

.sort(
.splice(
.fill(
.copyWithin(

and focus on expressions that call them directly on $json.xxx arrays.

If a large number of workflows depend on this pattern and you cannot regression-test them quickly, a controlled rollback may be reasonable. But n8n rollback decisions also involve database migrations, other node changes, credentials and your deployment process. Back up the database and workflows and test 2.34.5 before changing production.

A practical 2.35.3 triage sequence

If your symptom matches this article:

  1. Confirm the runtime is actually 2.35.3, including workers if you run a distributed setup.
  2. Keep the failing expression and input as a control.
  3. Change only the array access to a copy-first form and rerun the same item.
  4. If the copy-first version works, check whether the expression uses sort, splice, fill or copyWithin directly on $json.
  5. Restore the smallest failing point before refactoring the rest of the workflow.
  6. Audit other workflows for the same direct-mutation pattern.
  7. When upstream ships a fix, remove the workaround in a test instance first and compare outputs before changing production.

This is not the same n8n bug as yesterday’s HTTP Request stream issue

XBSTACK published a separate n8n HTTP Request Raw Body / _readableState troubleshooting article yesterday. The product is the same; the search intent is not.

That issue lives in the HTTP Request Raw Body + Response Format path and exposes a stream-shaped object instead of parsed JSON.

This issue lives in Edit Fields expression evaluation and returns null for several direct $json Array mutations after the 2.35.3 upgrade.

They therefore deserve separate URLs and separate reproduction assets. For broader workflow failure patterns, see the n8n workflow error-handling guide and the Workflow hub.

Evidence boundary and upstream tracking

As of August 19, 2026, I can state the following with local runtime evidence:

  • Upstream issue #36540 reports the same 2.35.3 regression.
  • XBSTACK reproduced the version difference with official 2.34.5 and 2.35.3 Docker images.
  • Direct sort/splice/fill/copyWithin calls on $json.data return null on 2.35.3 in the isolated Edit Fields test.
  • reverse() does not show the same failure.
  • Copy-first versions of all four affected methods pass on 2.35.3.

I am not claiming that a specific internal commit is the root cause, and I am not predicting a fix version before upstream publishes one.

Primary references:

When upstream ships a confirmed fix, this page should be updated with the affected/fixed version matrix instead of creating another duplicate troubleshooting URL.

Topic path / AI workflows

Continue through the production automation path

The workflow hub connects self-hosting, queue mode, webhooks, retries, observability and n8n implementation cases into one production-oriented learning path.

More to Explore

Topic hub →
n8n 2.33.4 Baserow Workflows Fail to Activate: Fix 'Could not resolve parameter dependencies'n8n Could not resolve parameter dependencies after 2.33.4? This Baserow repro compares 2.32.7 vs 2.33.4, isolates the timezone regression, and gives safe rollback steps.n8n HTTP Request Returns _readableState Instead of JSON: Raw Body Response Stream Fixn8n HTTP Request can return _readableState instead of JSON with Raw Body + explicit JSON Response. See the four-case repro, source path and tested workarounds.n8n 2.33.7 Distroless ARM64 GLIBC_PRIVATE Error: Reproduction and Workaroundn8n 2.33.7 distroless on ARM64 exits 127 with __tunable_is_initialized / GLIBC_PRIVATE. Compare 2.26.9, the Dockerfile ABI boundary, and a verified rollback workaround.n8n AI Agent Not Calling Tools: tool_choice, Provider Compatibility, and Memoryn8n AI Agent not calling tools: diagnose tool_choice, provider compatibility, tool schema and descriptions, result parsing, and memory when connected tools are skipped.

AI Engineering Weekly

Production changes, real failures, experiments and new XBSTACK assets.

Comments & evidence

DISCUSSION

Questions, verification and corrections

Sign in to comment. Every new comment is reviewed before publication; while pending, it is visible only to you and the administrator.

Sign-in required Reviewed before public
Loading the discussion…