n8n-io/n8n · error · Error

Cannot decrease maxIterations when resuming a run. Expected

Error message

Cannot decrease maxIterations when resuming a run. Expected >= ${persistedMaxIterations}, received ${callerMaxIterations}.

What it means

Thrown by the max-nodes validator when the number of instances of a single node type exceeds the maxNodes limit declared in that node type's description. Several n8n node types are singletons (e.g. one Schedule Trigger per workflow) and declare maxNodes=1; exceeding it is a structural error.

Source

Thrown at packages/@n8n/agents/src/runtime/loop/agent-runtime.ts:407

		}

		try {
			// Merge persisted execution options with fresh caller options
			const {
				runId: _rid,
				toolCallId: _tcid,
				onResumeClaimed: _onResumeClaimed,
				...callerExecOptions
			} = options;
			const persisted = state.executionOptions ?? {};
			const persistedMaxIterations = persisted.maxIterations;
			const callerMaxIterations = callerExecOptions.maxIterations;
			if (
				callerMaxIterations !== undefined &&
				persistedMaxIterations !== undefined &&
				callerMaxIterations < persistedMaxIterations
			) {
				throw new Error(
					`Cannot decrease maxIterations when resuming a run. Expected >= ${persistedMaxIterations}, received ${callerMaxIterations}.`,
				);
			}

			const mergedMaxIterations = callerMaxIterations ?? persistedMaxIterations;
			const mergedExecOptions: ExecutionOptions & { iterationCount?: number } = {
				...callerExecOptions,
				...(mergedMaxIterations !== undefined ? { maxIterations: mergedMaxIterations } : {}),
				...(state.iterationCount !== undefined ? { iterationCount: state.iterationCount } : {}),
			};

			const resumeOptions: RuntimeExecutionOptions = {
				persistence: state.persistence,
				...mergedExecOptions,
			};

			const claimed = await this.runState.claimResume(this.runId, state);
			if (!claimed) {

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Remove the extra instance(s) of the node type until count is within maxNodes.
  2. If you genuinely need parallel schedules or branches, restructure to use a single trigger feeding into a branch/merge instead of duplicate singleton nodes.
  3. Confirm the node type's maxNodes value via its description if you believe the limit is wrong.

Example fix

// before — two Schedule Trigger nodes in one workflow
scheduleTrigger({ name: 'Every Hour' });
scheduleTrigger({ name: 'Every Day' });

// after — one trigger, branch with a Switch/IF on time
const trigger = scheduleTrigger({ name: 'Run' });
// route to hourly vs daily logic downstream
Defensive patterns

Strategy: validation

Validate before calling

function countByType(nodes: Array<{ type: string }>): Map<string, number> {
  const m = new Map<string, number>();
  for (const n of nodes) m.set(n.type, (m.get(n.type) ?? 0) + 1);
  return m;
}

// before validating, check against each node type's maxNodes:
for (const [type, count] of countByType(allNodes)) {
  const max = nodeTypesProvider.getByNameAndVersion(type, version)?.description?.maxNodes;
  if (max !== undefined && count > max) throw new Error(`${type}: ${count} exceeds maxNodes ${max}`);
}

Prevention

When it happens

Trigger: After grouping nodes by type (count > 1), the validator resolves the first instance's version, looks up nodeType.description.maxNodes via the nodeTypesProvider, and fires when count > maxNodes. Only types that actually declare a numeric maxNodes are constrained.

Common situations: Adding a second Schedule Trigger or other singleton node; merging two workflows that each contained the same limited node type; an AI builder duplicating a trigger because it misread the requirement.

Related errors


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