windmill-labs/windmill · error

Duplicate group: '${g.start_id}' → '${g.end_id}'

Error message

Duplicate group: '${g.start_id}' → '${g.end_id}'

What it means

validateGroups in FlowYamlEditor.svelte rejects a flow that declares two identical group edges (same start_id and end_id pair). Duplicate branches between the same pair of modules make the flow graph ambiguous, so the editor refuses to apply the YAML.

Source

Thrown at frontend/src/lib/components/flows/header/FlowYamlEditor.svelte:57

		if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
			throw new Error('the document must be a mapping (key: value)')
		}
		const value = (parsed as Record<string, unknown>).value
		if (typeof value !== 'object' || value === null || Array.isArray(value)) {
			throw new Error("missing 'value' - paste a whole OpenFlow document, not just its value")
		}
		if (!Array.isArray((value as Record<string, unknown>).modules)) {
			throw new Error("'value.modules' must be a list")
		}
	}

	function validateGroups(groups: { start_id: string; end_id: string }[] | undefined) {
		if (!groups) return
		const seen = new Set<string>()
		for (const g of groups) {
			const key = `${g.start_id}:${g.end_id}`
			if (seen.has(key)) {
				throw new Error(`Duplicate group: '${g.start_id}' → '${g.end_id}'`)
			}
			seen.add(key)
		}
	}

	function apply() {
		try {
			const parsed = YAML.parse(code)
			validateShape(parsed)
			validateGroups(parsed.value?.groups)
			if (parsed.summary && typeof parsed.summary === 'string') {
				flowStore.val.summary = parsed.summary
			}
			if (parsed.description && typeof parsed.description === 'string') {
				flowStore.val.description = parsed.description
			}
			if (parsed['ws_error_handler_muted'] !== undefined) {
				flowStore.val.ws_error_handler_muted = parsed['ws_error_handler_muted']

View on GitHub (pinned to e474e8803c)

Solutions

  1. Remove one of the duplicated group entries so each (start_id, end_id) pair appears at most once
  2. If two branches between the same modules are intended, use branch indexes/conditional branch syntax instead of duplicate groups
  3. Ensure each group's start_id and end_id reference distinct, existing module ids
  4. Regenerate the YAML from the flow editor UI instead of hand-copying branch definitions

Example fix

// before (duplicate edge)
groups:
  - start_id: a
    end_id: b
  - start_id: a
    end_id: b
// after (single edge)
groups:
  - start_id: a
    end_id: b
Defensive patterns

Strategy: validation

Validate before calling

const seen = new Set()
for (const g of parsed.value.groups ?? []) {
  const key = `${g.start_id}:${g.end_id}`
  if (seen.has(key)) { alert(`Duplicate group ${key}`); break }
  seen.add(key)
}

Type guard

function hasUniqueGroups(groups: { start_id: string; end_id: string }[]): boolean {
  const keys = groups.map(g => `${g.start_id}:${g.end_id}`)
  return new Set(keys).size === keys.length
}

Try / catch

try {
  editor.apply(yamlText)
} catch (e) {
  if (e.message.startsWith('Duplicate group:')) {
    sendUserToast(e.message + ' — remove the repeated edge', true)
  }
}

Prevention

When it happens

Trigger: Calling apply() → validateGroups() when the parsed flow's groups array contains two entries with the same start_id:end_id key — e.g. copy-pasted branch definitions or two parent-children edges linking the same modules.

Common situations: Hand-editing YAML and duplicating a branch entry; merging two flow YAMLs where both defined a branch between the same modules; generating YAML programmatically and emitting the same branch twice.

Related errors


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