n8n-io/n8n · error · UnsupportedNodeError

Unsupported syntax: 'Unary operator ${node.operator}' is not

Error message

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

What it means

The interpreter supports five unary operators: `-` (negation), `+` (coercion), `!` (logical NOT), `typeof`, and `void`. All other unary operators throw `UnsupportedNodeError` at interpreter.ts:603. This includes `~` (bitwise NOT) and `delete` — the former is rarely needed and the latter mutates state.

Source

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

	/**
	 * Visit a unary expression.
	 */
	private visitUnaryExpression(node: ESTree.UnaryExpression): unknown {
		const arg = this.evaluate(node.argument);

		switch (node.operator) {
			case '-':
				return -(arg as number);
			case '+':
				return +(arg as number);
			case '!':
				return !arg;
			case 'typeof':
				return typeof arg;
			case 'void':
				return undefined;
			default:
				throw new UnsupportedNodeError(
					`Unary operator ${node.operator}`,
					node.loc ?? undefined,
					this.sourceCode,
				);
		}
	}

	/**
	 * Visit a binary expression.
	 */
	private visitBinaryExpression(node: ESTree.BinaryExpression): unknown {
		const left = this.evaluate(node.left as ESTree.Expression);
		const right = this.evaluate(node.right);

		switch (node.operator) {
			case '+':
				if (typeof left === 'string' || typeof right === 'string') {
					return String(left) + String(right);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. For `~`/bitwise: move to a Code node or n8n expression; use `Math.floor` or arithmetic
  2. For `delete`: use property reassignment to undefined (`obj.prop = undefined`) or move to Code node
  3. Restructure the expression to use only `-`, `+`, `!`, `typeof`

Example fix

// before
const truncated = ~~3.7;

// after
// (bitwise NOT not supported; move to Code node or use arithmetic)
const truncated = 3 < 0 ? -Math.floor(-3) : Math.floor(3); // in a Code node
// In SDK code, avoid truncation entirely
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED_UNARY = new Set(['-', '+', '!', 'typeof', 'void']);

function findBadUnaryOperators(code: string): string[] {
  const ast = parse(code, { ecmaVersion: 'latest', sourceType: 'module' });
  const bad: string[] = [];
  walk(ast, (node) => {
    if (node.type === 'UnaryExpression' && !ALLOWED_UNARY.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('Unary operator')) {
    // show allowed operators and suggest alternatives
  }
  throw e;
}

Prevention

When it happens

Trigger: Writing `~x` (bitwise NOT), `~~x` (truncate trick), or `delete obj.prop` in SDK code. The switch at interpreter.ts:591 only has cases for `-`, `+`, `!`, `typeof`, `void`.

Common situations: Using bitwise NOT for numeric tricks (`~~3.7` for truncation); `delete` for property removal; porting low-level or performance-oriented JS.

Related errors


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