windmill-labs/windmill · error

Duplicated node detected: ${module.id}

Error message

Duplicated node detected: ${module.id}

What it means

graphBuilder's addNode refuses to insert two graph nodes with the same id, since React Flow requires unique node ids. A duplicate means the same FlowModule (same id) was encountered twice while walking the flow's modules.

Source

Thrown at frontend/src/lib/components/graph/graphBuilder.svelte.ts:466

	try {
		if (!modules) {
			return { nodes: {}, edges: [] }
		}

		const nodes: NodeLayout[] = []
		const edges: Edge[] = []

		// Lookup map from module ID to the original reactive FlowModule objects.
		const moduleMap = new Map<string, FlowModule>()
		for (const m of getAllModules(modules, failureModule)) {
			moduleMap.set(m.id, m)
		}

		function addNode(module: FlowModule, extraData?: Record<string, any>) {
			const duplicated = nodes.find((n) => n.id === module.id)
			if (duplicated) {
				console.log('Duplicated node detected: ', module, duplicated)
				throw new Error(`Duplicated node detected: ${module.id}`)
			}

			nodes.push({
				id: module.id,
				data: {
					module: module,
					id: module.id,
					parentIds: [],
					eventHandlers: eventHandlers,
					testModuleState: extra.testModuleStates?.states?.[module.id],
					insertable: extra.insertable && !module.id.startsWith('subflow:'),
					editMode: extra.editMode,
					isOwner: extra.isOwner,
					assets: getFlowModuleAssets(module, extra.additionalAssetsMap),
					moduleAction: extra.moduleActions?.[module.id],
					...extraData
				},
				type: 'module',

View on GitHub (pinned to e474e8803c)

Solutions

  1. Open the flow JSON and give each duplicated step a unique id, then redeploy.
  2. In the editor, delete and re-add the duplicated step so it gets a fresh id.
  3. If the flow was generated by a script, fix the generator to assign unique ids per step.
  4. Check for accidental double-inclusion of child modules (branch/foreach inputs) and deduplicate.

Example fix

// before
[{ "id": "step1", ... }, { "id": "step1", ... }]
// after
[{ "id": "step1", ... }, { "id": "step2", ... }]
Defensive patterns

Strategy: validation

Validate before calling

const seen = new Set()
for (const m of modules) { if (seen.has(m.id)) console.warn('duplicate module id', m.id); seen.add(m.id) }

Type guard

function hasUniqueIds(modules) { return new Set(modules.map(m => m.id)).size === modules.length }

Try / catch

try { buildGraph(flow) } catch (e) { if (String(e.message).startsWith('Duplicated node detected')) reloadFlowWithFreshIds(); else throw e }

Prevention

When it happens

Trigger: processModules (or addFailureNode) encounters two FlowModule entries with identical module.id — e.g. the flow JSON literally lists the same step id twice, or a branch/foreach expansion re-emits a step already added.

Common situations: Hand-edited or programmatically generated flow JSON reusing a step id; copy-paste of a branch in the editor that duplicated ids; a backend/plugin bug emitting a module in both the main list and a child list.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/acd29ba2a3bf15ca. Report an issue: GitHub.