windmill-labs/windmill · error

Invalid flow modules:\n${errors.join('\n')}

Error message

Invalid flow modules:\n${errors.join('\n')}

What it means

After Array.isArray passes, validateFlowModules runs the modules through the Zod flowModulesSchema. On failure it formats up to 5 issues — attributing each to its module ID and field path where possible — and throws this aggregated error. It is the canonical 'your modules payload doesn't match the flow module schema' message.

Source

Thrown at frontend/src/lib/components/copilot/chat/flow/editableFlowJson.ts:251

					modulesSchema,
					path as (string | number)[],
					parsedModules
				)
				if (targetSchema) {
					const expectedFormat = getExpectedFormat(targetSchema)
					if (expectedFormat) {
						message += `\n    Expected format: ${expectedFormat}`
					}
				}
			}

			if (moduleId) {
				return `Module "${moduleId}" -> ${fieldPath}: ${message}`
			}
			return `${path.join('.')}: ${message}`
		})

		throw new Error(`Invalid flow modules:\n${errors.join('\n')}`)
	}

	const ids = collectAllFlowModuleIdsFromModules(parsedModules)
	if (ids.length !== new Set(ids).size) {
		throw new Error('Duplicate module IDs found in flow')
	}

	const reservedIds = ids.filter(
		(id) => id === SPECIAL_MODULE_IDS.PREPROCESSOR || id === SPECIAL_MODULE_IDS.FAILURE
	)
	if (reservedIds.length > 0) {
		throw new Error(
			'Special modules must be provided via preprocessor_module and failure_module, not inside modules'
		)
	}

	// Not expressible in the schema: `provider` is required only when the step is standalone, and
	// making AiAgent a conditional union breaks the FlowModuleValue discriminated union it belongs to.

View on GitHub (pinned to e474e8803c)

Solutions

  1. Read the per-module messages in the error (Module "<id>" -> <field>: <reason>) and fix exactly those fields.
  2. Ensure every module has a unique 'id' and a 'value' whose 'type' matches the schema union (rawscript, script, flow, branch, etc.).
  3. Supply all required fields for the chosen type — e.g. rawscript needs content, language, and tags/input_transforms in the right shapes.
  4. Model the payload on the current editable flow JSON output, which is guaranteed schema-conformant.

Example fix

// before: rawscript missing content
{ id: 'm1', value: { type: 'rawscript', language: 'python3' } }
// after
{ id: 'm1', value: { type: 'rawscript', language: 'python3', content: 'print(1)' } }
Defensive patterns

Strategy: validation

Validate before calling

import { flowModulesSchema } from './editableFlowJson'
const res = flowModulesSchema.safeParse(modules)
if (!res.success) console.error(res.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`))

Type guard

function modulesMatchSchema(v: unknown): v is FlowModule[] {
  return flowModulesSchema.safeParse(v).success
}

Try / catch

try {
  await setFlow({ modules })
} catch (e) {
  if (e.message.startsWith('Invalid flow modules:')) {
    // error lists each bad module as Module "<id>" -> <field>: <reason>
    fixListedFields(e.message)
  } else throw e
}

Prevention

When it happens

Trigger: validateFlowModules receiving an array whose entries violate flowModulesSchema: missing id, unknown/invalid value.type discriminator, missing required fields for the module type (e.g. rawscript without content/language), wrong input_transform shape, or invalid nested fields.

Common situations: The AI invents a module type not in the discriminated union; a required field like 'value.content' or 'value.language' is omitted for rawscript; transforms use the wrong key (expression vs value); a field intended for one module kind is put on another.

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/6a8cec574e89430b. Report an issue: GitHub.