windmill-labs/windmill · error

Flow groups must be an array

Error message

Flow groups must be an array

What it means

validateFlowGroups in helperUtils.ts normalizes the flow's visual 'groups' (editor note boxes) and first checks the raw input shape. Groups are optional; when provided (non-null) they must be a JSON array. Anything else — a string, object, number — is rejected with this error before per-group validation.

Source

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

	if (!module || module.value.type !== 'rawscript') {
		return undefined
	}

	const rawScriptModule = module as FlowModule & { value: RawScript }
	rawScriptModule.value.content = code
	return rawScriptModule
}

export function validateFlowGroups(
	rawGroups: unknown,
	moduleIds?: Set<string>
): FlowGroup[] | null {
	if (rawGroups == null) {
		return null
	}

	if (!Array.isArray(rawGroups)) {
		throw new Error('Flow groups must be an array')
	}

	return rawGroups.map((group, index) => {
		if (!group || typeof group !== 'object' || Array.isArray(group)) {
			throw new Error(`Invalid group at index ${index}: must be an object`)
		}
		const g = group as Record<string, unknown>
		if (typeof g.start_id !== 'string' || !g.start_id) {
			throw new Error(`Invalid group at index ${index}: start_id must be a non-empty string`)
		}
		if (typeof g.end_id !== 'string' || !g.end_id) {
			throw new Error(`Invalid group at index ${index}: end_id must be a non-empty string`)
		}
		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`
				)

View on GitHub (pinned to e474e8803c)

Solutions

  1. Pass groups as an array: [{ start_id, end_id, ... }]
  2. Omit/null out groups entirely if there are no groups
  3. Unwrap a wrapper object (e.g. { groups: [...] }) to the inner array before calling

Example fix

// before
validateFlowGroups({ default: { start_id: 'a', end_id: 'b' } })
// after
validateFlowGroups([{ summary: 'default', start_id: 'a', end_id: 'b' }])
Defensive patterns

Strategy: validation

Validate before calling

if (groups != null && !Array.isArray(groups)) throw new Error('groups must be an array or null')

Type guard

function isFlowGroups(v) {
  return v == null || (Array.isArray(v))
}

Try / catch

try {
  const groups = validateFlowGroups(raw.groups, moduleIds)
} catch (e) {
  if (e.message === 'Flow groups must be an array') {
    return null // drop groups and continue without visual grouping
  }
  throw e
}

Prevention

When it happens

Trigger: Calling validateFlowGroups (via the flowTools 'groups' argument or result validation) with groups set to a non-array non-null value, e.g. groups: {} or groups: "default".

Common situations: LLM emitting groups as a map keyed by name instead of an array; client sending the whole groups object wrapper rather than its array value; JSON schema mismatch after an API version change.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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