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
- Set failure_module.id to the exact required constant shown in the error message (SPECIAL_MODULE_IDS.FAILURE).
- Ensure failure_module.value.type is "rawscript" or "script" (a sibling check throws otherwise).
- 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
- Copy SPECIAL_MODULE_IDS.FAILURE into generated failure modules
- Never assign fresh UUIDs to special modules
- Preserve the special id when moving a module into failure_module
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
- Invalid preprocessor_module: id must be "${SPECIAL_MODULE_ID
- Invalid ${fieldName}: ${error?.message ?? 'unknown error'}
- Invalid preprocessor_module: only "rawscript" and "script" m
- result.substring(__RESULT_ERR_PREFIX.length)
- Invalid migration name '${name}': use only letters, digits,
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/8c380a73f500e7ef.
Report an issue: GitHub.