n8n-io/n8n · error · Error
.onTrue() is only available on IF nodes (${NODE_TYPES.IF})
Error message
.onTrue() is only available on IF nodes (${NODE_TYPES.IF}) What it means
Thrown by NodeInstanceImpl.onTrue() when isIfNodeType(this.type) returns false. The .onTrue()/.onFalse() branch builders target the true/false output ports that only exist on n8n-nodes-base.if nodes; calling onTrue on any other node type is rejected because those ports do not exist.
Source
Thrown at packages/@n8n/workflow-sdk/src/workflow-builder/node-builders/node-builder.ts:315
*/
output(index: number): OutputSelector<TType, TVersion, TOutput> {
return new OutputSelectorImpl(this, index) as unknown as OutputSelector<
TType,
TVersion,
TOutput
>;
}
/**
* Start building an IF branch with the true branch target.
* Only available on IF nodes (n8n-nodes-base.if).
*
* @example
* ifNode.onTrue(trueHandler).onFalse(falseHandler)
*/
onTrue(target: IfElseTarget): IfElseBuilder<TOutput> {
if (!isIfNodeType(this.type)) {
throw new Error(`.onTrue() is only available on IF nodes (${NODE_TYPES.IF})`);
}
const builder = new IfElseBuilderImpl<TOutput>(
this as unknown as NodeInstance<'n8n-nodes-base.if', string, TOutput>,
);
return builder.onTrue(target);
}
/**
* Start building an IF branch with the false branch target.
* Only available on IF nodes (n8n-nodes-base.if).
*
* @example
* ifNode.onFalse(falseHandler).onTrue(trueHandler)
*/
onFalse(target: IfElseTarget): IfElseBuilder<TOutput> {
if (!isIfNodeType(this.type)) {
throw new Error(`.onFalse() is only available on IF nodes (${NODE_TYPES.IF})`);
}View on GitHub (pinned to 5ac6606e81)
Solutions
- Create the node with type 'n8n-nodes-base.if' before calling .onTrue().
- For Switch nodes use .onCase(index, target); for plain fan-out use .to().
- Type-narrow with isIfNodeType before calling .onTrue()/.onFalse().
Example fix
// before
const n = node('n8n-nodes-base.switch', 'v1', { ... });
n.onTrue(handler); // throws
// after
const ifNode = node('n8n-nodes-base.if', 'v1', { ... });
ifNode.onTrue(handler).onFalse(otherHandler); Defensive patterns
Strategy: type-guard
Validate before calling
function assertIfNode(node: NodeInstance): asserts node is NodeInstance<'n8n-nodes-base.if', string, unknown> {
if (node.type !== 'n8n-nodes-base.if') {
throw new Error(`.onTrue() requires an IF node, got ${node.type}`);
}
}
assertIfNode(myNode);
myNode.onTrue(handler); Type guard
import { isIfNodeType } from '@n8n/workflow-sdk';
function isIfNode(node: NodeInstance): node is NodeInstance<'n8n-nodes-base.if', string, unknown> {
return isIfNodeType(node.type);
} Prevention
- Create IF nodes explicitly with node('n8n-nodes-base.if', ...).
- Narrow with isIfNodeType before calling .onTrue()/.onFalse().
- Reserve .onTrue()/.onFalse() for IF nodes; use .onCase() for Switch and .to() for plain fan-out.
When it happens
Trigger: Calling someNode.onTrue(handler) where someNode is a Switch, Code, HTTP, Merge, or any non-IF node type. Passing a generic NodeInstance to a helper that unconditionally calls .onTrue().
Common situations: Wrong node type selected (e.g. used Switch instead of IF); copy-paste from an IF example onto another node; dynamic node construction where the type string is wrong.
Related errors
- .onFalse() is only available on IF nodes (${NODE_TYPES.IF})
- .onCase() is only available on Switch nodes (${NODE_TYPES.SW
- SDK_REPEATED_BRANCH_WIRING
- SplitInBatches node input connections are managed by SplitIn
- SplitInBatches node output connections are managed by SplitI
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/974480301583162d.
Report an issue: GitHub.