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
- Pass groups as an array: [{ start_id, end_id, ... }]
- Omit/null out groups entirely if there are no groups
- 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
- Always serialize groups as a JSON array of objects
- Pass null/undefined when there are no groups instead of {}
- Unwrap any { groups: [...] } wrapper before calling the tool
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
- Invalid group at index ${index}: must be an object
- result.substring(__RESULT_ERR_PREFIX.length)
- Flow modules must be an array
- Invalid group at index ${index}: start_id must be a non-empt
- Invalid group at index ${index}: end_id must be a non-empty
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/94ae188a21dda4f8.
Report an issue: GitHub.