windmill-labs/windmill · error

Duplicate group: ' ' →

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.

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.

Appendix: 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)