windmill-labs/windmill · error · Error

Invalid group at index ${index}: end_id "${g.end_id}" does n

Error message

Invalid group at index ${index}: end_id "${g.end_id}" does not match any flow module

What it means

validateFlowGroups checks that each group's end_id references an existing flow module when a moduleIds set is provided. This error is thrown when end_id does not match any module. It prevents a group box whose end boundary points at a non-existent node on the flow canvas.

Source

Thrown at frontend/src/lib/components/copilot/chat/flow/helperUtils.ts:124

		}
		if (moduleIds) {
			if (!moduleIds.has(g.start_id)) {
				throw new Error(
					`Invalid group at index ${index}: start_id "${g.start_id}" does not match any flow module`
				)
			}
			if (!moduleIds.has(g.end_id)) {
				throw new Error(
					`Invalid group at index ${index}: end_id "${g.end_id}" does not match any flow module`
				)
			}
		}
		if (g.color !== undefined && g.color !== null) {
			if (typeof g.color !== 'string' || !ALLOWED_NOTE_COLORS.has(g.color)) {
				throw new Error(
					`Invalid group at index ${index}: color must be one of ${[...ALLOWED_NOTE_COLORS].join(', ')}`
				)
			}
		}
		return g as unknown as FlowGroup
	})
}

/**
 * Validate the optional array of sticky notes the agent attached to the flow.
 * Notes are editor-only annotations and do not affect execution.
 *
 * `free` notes are the supported kind (standalone canvas annotations). The
 * `group` note type is deprecated for creation — the chat prompt steers the
 * agent toward `groups` instead — but it is still ACCEPTED here so flows that
 * already contain group notes round-trip cleanly through `patch_flow_json` /
 * `set_flow_json` rather than being rejected. When `moduleIds` is provided,
 * every `contained_node_ids` entry of a `group` note must reference an existing
 * module.
 *
 * A provided palette `color` is always preserved as-is; the default is only

View on GitHub (pinned to e474e8803c)

Solutions

  1. Use the exact `id` of an existing module from the flow value for end_id
  2. Re-read the current flow JSON to confirm module ids before writing groups
  3. Ensure the target end module exists in the same update if the group is meant to wrap a newly added module
  4. Remove or correct the group at the reported index

Example fix

// before
groups: [{ start_id: 'a1b2', end_id: 'last_step' }]
// after
groups: [{ start_id: 'a1b2', end_id: flow.value.modules[flow.value.modules.length - 1].id }]
Defensive patterns

Strategy: validation

Validate before calling

const moduleIds = new Set(flow.value.modules.map((m) => m.id));
for (const [i, g] of (groups ?? []).entries()) {
  if (!moduleIds.has(g.end_id)) throw new Error(`groups[${i}].end_id "${g.end_id}" is not a flow module id`);
}

Type guard

function isValidGroupId(id: unknown, moduleIds: Set<string>): id is string {
  return typeof id === 'string' && moduleIds.has(id);
}

Try / catch

try {
  validateFlowGroups(rawGroups, moduleIds);
} catch (e) {
  if (e instanceof Error && /end_id .* does not match/.test(e.message)) {
    console.error('Group end_id unknown — re-fetch flow JSON and retry with real ids');
  } else throw e;
}

Prevention

When it happens

Trigger: patch_flow_json / set_flow_json called with groups where g.end_id (e.g. 'mod_final') is not a key in the moduleIds set built from the flow's modules — typically a hallucinated or stale id.

Common situations: LLM agent copies a start_id correctly but invents the end_id; the end module was removed by a previous tool call in the same session; ids were truncated or reformatted by the model.

Related errors


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