n8n-io/n8n · warning

SDK_CODE_AFTER_EXPORT_DEFAULT

SDK_CODE_AFTER_EXPORT_DEFAULT

Error message

Statement after `export default workflow(...)` never reaches the builder — nodes/wiring here are dropped. Compose all `.to()` / `.onTrue()` / `.onFalse()` / `.onCase()` inside the export default chain.

What it means

SDK_CODE_AFTER_EXPORT_DEFAULT is a lint issue. lintWorkflowSdkAst() finds the ExportDefaultDeclaration index and flags every non-EmptyStatement after it, because any node construction or wiring (.to()/.onTrue()/etc.) written as a separate top-level statement after export default is dropped — the builder only consumes the export default chain.

Source

Thrown at packages/@n8n/workflow-sdk/src/lint/sdk/workflow-sdk-lint.ts:195

			lintIssue({
				code: 'SDK_AS_CONST',
				message:
					'`as const` is TypeScript-only and the workflow parser cannot interpret it. Remove the assertion.',
				line: match.line,
				column: match.column + 1,
				lintTarget: 'sdk',
			}),
		);
	}

	const exportIndex = ast.body.findIndex((stmt) => stmt.type === 'ExportDefaultDeclaration');
	if (exportIndex >= 0) {
		for (let i = exportIndex + 1; i < ast.body.length; i++) {
			const stmt = ast.body[i];
			if (!stmt || stmt.type === 'EmptyStatement') continue;
			issues.push(
				lintIssue({
					code: 'SDK_CODE_AFTER_EXPORT_DEFAULT',
					message:
						'Statement after `export default workflow(...)` never reaches the builder — nodes/wiring here are dropped. ' +
						'Compose all `.to()` / `.onTrue()` / `.onFalse()` / `.onCase()` inside the export default chain.',
					...locationOf(stmt),
					lintTarget: 'sdk',
				}),
			);
		}
	}

	const branchCounts = new Map<string, { count: number; line?: number; column?: number }>();

	walkAst(
		ast,
		(node, parent) => {
			if (node.type === 'ImportDeclaration') return;

			const forbidden = FORBIDDEN_NODE_TYPES[node.type];

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Move all .to()/.onTrue()/.onFalse()/.onCase()/.onDone() calls inside the single export default chain.
  2. Delete any stray top-level statements after export default.
  3. Restructure so the entire workflow is one fluent expression terminating at export default.

Example fix

// before
export default workflow().to(a);
a.to(b);
b.onTrue(c);
// after
export default workflow().to(a).to(b).onTrue(c);
Defensive patterns

Strategy: validation

Validate before calling

import { lintWorkflowSource } from '@n8n/workflow-sdk/lint/lint-workflow-source';
const issues = lintWorkflowSource(sdkSource);
if (issues.some((i) => i.code === 'SDK_CODE_AFTER_EXPORT_DEFAULT')) {
  throw new Error('Statements after export default are dropped; fold all wiring into the export default chain.');
}

Prevention

When it happens

Trigger: export default workflow().to(a); a.to(b); — or any node construction, assignment, or wiring call appearing as a top-level statement after the export default line.

Common situations: Agent adds wiring as separate statements instead of chaining; developer appends nodes 'after' the export; refactor leaves orphan statements.

Related errors


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