n8n-io/n8n · error · UnsupportedNodeError

Unsupported syntax: 'Binary operator ${node.operator}' is no

Error message

Unsupported syntax: 'Binary operator ${node.operator}' is not allowed in SDK code

What it means

Binary operators are restricted to arithmetic (`+`, `-`, `*`, `/`, `%`, `**`) and comparison (`==`, `!=`, `===`, `!==`, `<`, `<=`, `>`, `>=`). Bitwise operators (`|`, `&`, `^`, `<<`, `>>`, `>>>`) and relational operators (`in`, `instanceof`) throw `UnsupportedNodeError` at interpreter.ts:653 because they are rarely needed for workflow construction and bitwise ops are a common obfuscation vector.

Source

Thrown at packages/@n8n/workflow-sdk/src/ast-interpreter/interpreter.ts:653

				// eslint-disable-next-line eqeqeq
				return left == right;
			case '!=':
				// eslint-disable-next-line eqeqeq
				return left != right;
			case '===':
				return left === right;
			case '!==':
				return left !== right;
			case '<':
				return (left as number) < (right as number);
			case '<=':
				return (left as number) <= (right as number);
			case '>':
				return (left as number) > (right as number);
			case '>=':
				return (left as number) >= (right as number);
			default:
				throw new UnsupportedNodeError(
					`Binary operator ${node.operator}`,
					node.loc ?? undefined,
					this.sourceCode,
				);
		}
	}

	/**
	 * Visit a logical expression.
	 */
	private visitLogicalExpression(node: ESTree.LogicalExpression): unknown {
		const left = this.evaluate(node.left);

		switch (node.operator) {
			case '&&':
				return left ? this.evaluate(node.right) : left;
			case '||':
				// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- Implementing JS || semantics

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. For `in` checks: use property access and compare: `obj.prop !== undefined` or `obj.prop != null`
  2. For `instanceof`: use `typeof` (supported) or move to a Code node
  3. For bitwise ops: move to a Code node or n8n expression

Example fix

// before
const hasName = 'name' in obj;

// after
const hasName = obj.name !== undefined;
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED_BINARY = new Set(['+','-','*','/','%','**','==','!=','===','!==','<','<=','>','>=']);

function findBadBinaryOperators(code: string): string[] {
  const ast = parse(code, { ecmaVersion: 'latest', sourceType: 'module' });
  const bad: string[] = [];
  walk(ast, (node) => {
    if (node.type === 'BinaryExpression' && !ALLOWED_BINARY.has(node.operator)) {
      bad.push(node.operator);
    }
  });
  return bad;
}

Try / catch

import { UnsupportedNodeError } from '@n8n/workflow-sdk/ast-interpreter/errors';

try {
  interpretSDKCode(sdkCode, sdkFunctions);
} catch (e) {
  if (e instanceof UnsupportedNodeError && e.message.includes('Binary operator')) {
    // show allowed operators and suggest property-access alternatives for `in`
  }
  throw e;
}

Prevention

When it happens

Trigger: Writing `a | b`, `x in obj`, `y instanceof Z`, `n << 2`, or any bitwise/relational binary operator in SDK code. The switch at interpreter.ts:618 only has cases for the thirteen allowed operators.

Common situations: Bitwise flag manipulation; `in` operator for property existence checks; `instanceof` for type testing; porting algorithmic or low-level JS.

Related errors


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