An easy shape to get wrong by analogy
n8n's partial-workflow-update API accepts a whole family of diff operation types in a single array — addNode, addConnection, removeConnection, updateName, activateWorkflow, and more, including updateNode itself. Several of these take their target fields directly on the operation object: addConnection wants source and target right there, not nested inside anything. Writing updateNode the same way — putting name and a dotted parameters.rule.interval path straight on the operation, next to type and nodeId — is a completely reasonable guess based on how its sibling operations are shaped. It's also wrong.
What the error actually said
The rejected call came back with: Missing required parameter 'updates'. The updateNode operation requires an 'updates' object. Correct structure: {type: "updateNode", nodeId: "abc-123" OR nodeName: "My Node", updates: {name: "New Name", "parameters.url": "https://example.com"}}. That message is unusually good as API errors go — it names the exact missing key and even shows a worked example inline. The mistake on the calling side was pattern-matching against a different operation's shape from memory, then not re-reading the error's own correct-structure example closely enough the first time, and retrying the identical flat payload once more before actually changing anything.
The actual rule
updateNode is the one operation in this API whose target fields live inside a nested updates object rather than flat on the operation itself: {type: "updateNode", nodeId: "...", updates: {name: "...", "parameters.rule.interval": [...]}}. Everything that changes about the node — its display name, any dotted parameter path, disabled, onError, credentials — goes inside that one updates key, never as a sibling of type/nodeId. Connection-oriented operations like addConnection and removeConnection don't follow this pattern at all; their fields genuinely are flat. There isn't a single consistent rule across every operation type in this API — each one has to be checked on its own rather than inferred from a neighboring operation that happens to look similar.
Why the second identical attempt happened at all
The first error's example payload was right there in the response text. Retrying the exact same broken shape a second time, rather than reading that example and adjusting immediately, cost one extra round trip for no reason — a reminder that a documentation-quality error message is only useful if it's actually read on the first failure, not skimmed past on the way to a second attempt at the same guess.
The fix, and the general habit
Wrap every field that should change into the operation's updates object, keeping only type and the node identifier (nodeId or nodeName) outside it: {type: "updateNode", nodeId: "trigger-id", updates: {name: "Schedule Trigger - 1x Daily", "parameters.rule.interval": [{"triggerAtHour": 7}]}}. More generally, when an API supports several operation "types" through one shared array parameter, don't assume they share a payload shape just because they share a family — check each operation's own documented structure before the first call, especially for the ones whose name suggests a direct analogy to one you've already used successfully.
Operation shapes side by side
The operations I use most often with this API, written out in full, so the nesting is visible:
// Change a node: fields go inside "updates"
{ "type": "updateNode", "nodeName": "Schedule Trigger",
"updates": { "name": "Schedule Trigger - 1x Daily",
"parameters.rule.interval": [{ "triggerAtHour": 7 }] } }
// Add a connection: fields are flat
{ "type": "addConnection", "source": "IF - Ready", "target": "Upload", "sourceOutput": "true" }
// Remove a connection: also flat
{ "type": "removeConnection", "source": "IF - Ready", "target": "Old Node" }
// Rename the workflow: flat
{ "type": "updateName", "name": "WF - Publisher" }
The pattern is easy to remember once seen: anything that changes properties of an existing node goes inside updates, and everything else names its fields directly.
Dotted paths versus whole objects
Inside updates, a dotted key such as "parameters.rule.interval" changes one value and leaves the rest of parameters alone. Passing "parameters": { ... } instead replaces the whole parameters object, and every field you left out is gone. For a one-field change the dotted path is the safer choice. When I do replace a whole object, I first read the node's current parameters and edit that copy.
The same applies to node settings that live outside parameters, such as onError, retryOnFail, maxTries and waitBetweenTries. They are top-level node properties, so the key is just "retryOnFail": true inside updates.
Checking the change actually landed
A successful response only says the request was accepted. After every partial update I read the workflow back and compare the one node I changed. Two things are worth knowing:
- An editor tab that was open on the same workflow before the API change can save its old copy back over it. Close or reload open tabs first.
- For an active workflow, check that the active version has the change, not just the draft. Some changes only take effect after the workflow is deactivated and activated again.
Frequently asked questions
What does 'Missing required parameter updates' mean?
The updateNode operation expects every field you want to change inside a nested updates object. Fields placed directly on the operation next to type and nodeId are rejected.
Do addConnection and removeConnection also need an updates object?
No. Connection operations take their fields such as source and target directly on the operation object.
Is it safer to use a dotted path or a full parameters object?
A dotted path such as parameters.url changes one value. A full parameters object replaces everything, and any field you left out is removed.
How do I confirm a partial update worked?
Read the workflow back after the call and compare the changed node. Also make sure no open editor tab saves an older copy over your change.
n8n Automation Hub