windmill-labs/windmill · error

Invalid failure_module: id must be "${SPECIAL_MODULE_IDS.FAI

Error message

Invalid failure_module: id must be "${SPECIAL_MODULE_IDS.FAILURE}"

What it means

If a failure_module is supplied, its `id` must be the reserved SPECIAL_MODULE_IDS.FAILURE value; the failure handler is a distinguished module identified by that fixed id. Any other id would not be recognized as the failure handler by the backend, so it is rejected at edit time.

Source

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

	if (preprocessorModule) {
		if (preprocessorModule.id !== SPECIAL_MODULE_IDS.PREPROCESSOR) {
			throw new Error(
				`Invalid preprocessor_module: id must be "${SPECIAL_MODULE_IDS.PREPROCESSOR}"`
			)
		}
		if (
			preprocessorModule.value.type !== 'rawscript' &&
			preprocessorModule.value.type !== 'script'
		) {
			throw new Error(
				'Invalid preprocessor_module: only "rawscript" and "script" modules are supported'
			)
		}
	}
	if (failureModule) {
		if (failureModule.id !== SPECIAL_MODULE_IDS.FAILURE) {
			throw new Error(`Invalid failure_module: id must be "${SPECIAL_MODULE_IDS.FAILURE}"`)
		}
		if (failureModule.value.type !== 'rawscript' && failureModule.value.type !== 'script') {
			throw new Error('Invalid failure_module: only "rawscript" and "script" modules are supported')
		}
	}

	const ids = new Set(collectAllFlowModuleIdsFromModules(modules))
	if (preprocessorModule) {
		if (ids.has(preprocessorModule.id)) {
			throw new Error(`Duplicate module ID found in preprocessor_module: ${preprocessorModule.id}`)
		}
		ids.add(preprocessorModule.id)
	}
	if (failureModule && ids.has(failureModule.id)) {
		throw new Error(`Duplicate module ID found in failure_module: ${failureModule.id}`)
	}

	return {

View on GitHub (pinned to e474e8803c)

Solutions

  1. Set failure_module.id to the exact required constant shown in the error message (SPECIAL_MODULE_IDS.FAILURE).
  2. Ensure failure_module.value.type is "rawscript" or "script" (a sibling check throws otherwise).
  3. Re-run the tool after fixing the id.

Example fix

// before
{"failure_module":{"id":"on_failure",...}}
// after
{"failure_module":{"id":"failure",...}}
Defensive patterns

Strategy: validation

Validate before calling

import { SPECIAL_MODULE_IDS } from '../shared'
if (flow.failure_module && flow.failure_module.id !== SPECIAL_MODULE_IDS.FAILURE)
  throw new Error(`failure_module.id must be ${SPECIAL_MODULE_IDS.FAILURE}`)

Try / catch

try {
  validateEditableFlowJson(raw)
} catch (e) {
  if (String(e.message).startsWith('Invalid failure_module: id')) {
    raw.failure_module.id = SPECIAL_MODULE_IDS.FAILURE
    return validateEditableFlowJson(raw)
  }
  throw e
}

Prevention

When it happens

Trigger: Calling flowTools modules/patches with failure_module whose id is e.g. "failure_handler", "on_failure", or a copied regular module id instead of SPECIAL_MODULE_IDS.FAILURE.

Common situations: An LLM invents a descriptive id for the failure module; a regular error-handling script is moved into failure_module without re-id'ing it; renaming during a template edit.

Related errors


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