windmill-labs/windmill · error
Invalid group at index ${index}: start_id must be a non-empt
Error message
Invalid group at index ${index}: start_id must be a non-empty string What it means
Each flow group must specify start_id as a non-empty string naming the module where the group (note box) begins. validateFlowGroups throws at the given index when start_id is missing, not a string, or an empty string.
Source
Thrown at frontend/src/lib/components/copilot/chat/flow/helperUtils.ts:102
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`
)
}
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)) {View on GitHub (pinned to e474e8803c)
Solutions
- Set start_id to the string id of an existing flow module
- Remove the group if it has no meaningful start
- Ensure the id matches the module's id exactly (case-sensitive)
Example fix
// before
groups: [{ end_id: 'b' }]
// after
groups: [{ start_id: 'a', end_id: 'b' }] Defensive patterns
Strategy: validation
Validate before calling
for (const [i, g] of (groups ?? []).entries()) {
if (typeof g.start_id !== 'string' || !g.start_id)
throw new Error(`groups[${i}].start_id must be a non-empty string`)
} Type guard
function hasValidStartId(g) {
return typeof g?.start_id === 'string' && g.start_id.length > 0
} Try / catch
try {
const groups = validateFlowGroups(raw, moduleIds)
} catch (e) {
if (e.message.includes('start_id must be a non-empty string')) {
const idx = Number(e.message.match(/index (\d+)/)?.[1])
raw[idx].start_id = raw[idx].end_id // single-module group fallback
return validateFlowGroups(raw, moduleIds)
}
throw e
} Prevention
- Always set both start_id and end_id when defining a group
- Substitute template placeholders before validating, never after
- Copy module ids programmatically from the flow JSON rather than typing them
When it happens
Trigger: Calling validateFlowGroups with a group object lacking start_id, having start_id: "", or a non-string value like start_id: 3 or null.
Common situations: LLM emitting only an end_id; empty-string ids from template placeholders that were never substituted; numeric ids from another system.
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}: end_id must be a non-empty
- Flow groups must be an array
- Invalid group at index ${index}: must be an object
- Invalid group at index ${index}: start_id "${g.start_id}" do
- Invalid group at index ${index}: end_id "${g.end_id}" does n
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/871aec4ee13dddf2.
Report an issue: GitHub.