n8n-io/n8n · error · Error

Imports are not supported

Error message

Imports are not supported

What it means

Error('Imports are not supported') is thrown by jsVariablePolyfill's visitor when it encounters a visitImportExpression, i.e. a dynamic import() call inside an n8n expression. Static import statements would have already failed parsing for an expression context, so this guard specifically catches the dynamic form.

Solutions

  1. Use a Code node (JavaScript) which supports require() for permitted modules, instead of an inline expression.
  2. If a helper value is needed in the expression, compute it upstream in a Set/Code node and reference the field via $json / $node[...].
  3. Remove any import() call from inside {{ }}.

Example fix

// before
{{ (await import('lodash')).get($json, 'a.b') }}
// after
# In a Code node upstream:
#   const _ = require('lodash');
#   return [{ json: { val: _.get($input.all()[0].json, 'a.b') } }];
# Then in the expression: {{ $json.val }}
Defensive patterns

Strategy: validation

Validate before calling

// Reject dynamic import() in expressions at authoring time.
if (/\\bimport\\s*\\(/.test(codeChunk)) {
  throw new Error('dynamic import() is not supported in n8n expressions');
}

Type guard

import { namedTypes } from 'ast-types';
function isImportExpression(node: unknown): node is namedTypes.ImportExpression {
  return !!node && (node as any).type === 'ImportExpression';
}

Try / catch

try {
  const compiled = buildExpression(chunks, hooks);
} catch (e) {
  if (e instanceof Error && /Imports are not supported/.test(e.message)) {
    throw new UserError('import() is blocked in expressions; use a Code node with require().');
  }
  throw e;
}

Prevention

When it happens

Trigger: An n8n expression chunk contains a dynamic import, e.g. '{{ import("lodash") }}' or '{{ await import("./helper") }}'.

Common situations: A user expects to load a library on the fly from an expression; a pasted code snippet uses dynamic import for code splitting; a user attempts to reach Node built-ins via import.

Related errors


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

Appendix: source

Thrown at packages/@n8n/tournament/src/VariablePolyfill.ts:128

	},
	ArrowFunctionExpression(path, parent: namedTypes.ArrowFunctionExpression, dataNode) {
		// A concise arrow body that is a bare identifier (`() => process`) must be
		// routed through the data context like any other free read. Params are not
		// the body, and body identifiers that reference a param are left alone by
		// polyfillVar's in-scope check.
		if (parent.body === path.node) {
			polyfillVar(path, dataNode);
		}
	},
};

export const jsVariablePolyfill = (
	ast: types.namedTypes.File,
	dataNode: DataNode,
): StatementKind[] | undefined => {
	visit(ast, {
		visitImportExpression(_path) {
			throw new Error('Imports are not supported');
		},
		visitIdentifier(path) {
			this.traverse(path);
			const parent: ParentKind = path.parent.node;

			// This is for tmpl compat
			if (EXEMPT_IDENTIFIER_LIST.includes(path.node.name)) {
				return;
			}

			switch (parent.type) {
				case 'AssignmentPattern':
				case 'Property':
				case 'MemberExpression':
				case 'OptionalMemberExpression':
				case 'VariableDeclarator':
				case 'ArrowFunctionExpression':
					if (!customPatches[parent.type]) {

View on GitHub (pinned to 5ac6606e81)