n8n-io/n8n · error · Error

Nodes from fromJSON() do not support to()

Error message

Nodes from fromJSON() do not support to()

What it means

Nodes produced by fromJSON() are read-only snapshots: their connections are already fully described in the imported JSON, so the fluent connection-builder methods are intentionally disabled. The .to() method throws because re-wiring an imported node would conflict with the connections already encoded in the JSON. Only nodes authored via the builder factories (trigger/node/etc.) support the fluent .to()/.input()/.output()/.onError() API.

Source

Thrown at packages/@n8n/workflow-sdk/src/workflow-builder/workflow-import.ts:94

				...({ _originalName: n8nNode.name } as Record<string, unknown>),
				position: n8nNode.position,
				webhookId: n8nNode.webhookId,
				disabled: n8nNode.disabled,
				notes: n8nNode.notes,
				notesInFlow: n8nNode.notesInFlow,
				executeOnce: n8nNode.executeOnce,
				retryOnFail: n8nNode.retryOnFail,
				maxTries: n8nNode.maxTries,
				waitBetweenTries: n8nNode.waitBetweenTries,
				alwaysOutputData: n8nNode.alwaysOutputData,
				onError: n8nNode.onError,
				extendsCredential: n8nNode.extendsCredential,
			},
			update(config) {
				return { ...this, config: { ...this.config, ...config } };
			},
			to() {
				throw new Error('Nodes from fromJSON() do not support to()');
			},
			input() {
				throw new Error('Nodes from fromJSON() do not support input()');
			},
			output() {
				throw new Error('Nodes from fromJSON() do not support output()');
			},
			onError() {
				throw new Error('Nodes from fromJSON() do not support onError()');
			},
			getConnections() {
				return [];
			},
		};

		const connectionsMap = new Map<string, Map<number, ConnectionTarget[]>>();
		let mapKey = nodeName || `__unnamed_${unnamedCounter++}`;

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. If you need to extend an imported workflow, re-author the relevant nodes with the builder factories (trigger/node) instead of mutating imported handles.
  2. Use the workflow builder's .connect(source, sourceOutput, target, targetInput) method to add connections at the workflow level rather than via node.to().
  3. Edit the source JSON before calling fromJSON() to inject the desired connections.

Example fix

// before
const wf = workflow.fromJSON(json);
wf.getNode('MyNode').to(otherNode); // throws

// after
const wf = workflow.fromJSON(json);
wf.connect(importedNode, 0, otherNode, 0);
Defensive patterns

Strategy: type-guard

Validate before calling

function supportsFluentAPI(node: unknown): boolean {
  // Imported nodes' to() throws; authored nodes' to() returns a chain.
  // Track origin separately rather than probing at runtime.
  return (node as any)?.__imported !== true;
}

Type guard

import type { NodeInstance } from 'workflow-sdk';

function isAuthoredNode(n: NodeInstance & { __imported?: boolean }): boolean {
  return n.__imported !== true;
}

Try / catch

try {
  importedNode.to(target);
} catch (e) {
  if (e instanceof Error && e.message.includes('fromJSON()')) {
    wf.connect(importedNode, 0, target, 0);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling fromJSON(workflowJson) to import a workflow, then taking a node handle from the result and invoking node.to(target) to add a new outgoing connection. Also triggered by helpers that internally call .to() on an imported node handle.

Common situations: A user imports an existing n8n workflow JSON and tries to extend it imperatively; migration scripts that mix fromJSON import with builder-style chaining; code that treats all node handles uniformly without distinguishing authored vs imported nodes.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/26d9e673e31406b4. Report an issue: GitHub.