{"record":{"id":"39bc243c9cd9ce58","repo":"windmill-labs/windmill","slug":"duplicate-module-id-found-in-failure-module-fai","errorCode":null,"errorMessage":"Duplicate module ID found in failure_module: ${failureModule.id}","messagePattern":"Duplicate module ID found in failure_module: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/flow/editableFlowJson.ts","lineNumber":409,"sourceCode":"\t}\n\tif (failureModule) {\n\t\tif (failureModule.id !== SPECIAL_MODULE_IDS.FAILURE) {\n\t\t\tthrow new Error(`Invalid failure_module: id must be \"${SPECIAL_MODULE_IDS.FAILURE}\"`)\n\t\t}\n\t\tif (failureModule.value.type !== 'rawscript' && failureModule.value.type !== 'script') {\n\t\t\tthrow new Error('Invalid failure_module: only \"rawscript\" and \"script\" modules are supported')\n\t\t}\n\t}\n\n\tconst ids = new Set(collectAllFlowModuleIdsFromModules(modules))\n\tif (preprocessorModule) {\n\t\tif (ids.has(preprocessorModule.id)) {\n\t\t\tthrow new Error(`Duplicate module ID found in preprocessor_module: ${preprocessorModule.id}`)\n\t\t}\n\t\tids.add(preprocessorModule.id)\n\t}\n\tif (failureModule && ids.has(failureModule.id)) {\n\t\tthrow new Error(`Duplicate module ID found in failure_module: ${failureModule.id}`)\n\t}\n\n\treturn {\n\t\tmodules,\n\t\tschema,\n\t\tpreprocessor_module: preprocessorModule,\n\t\tfailure_module: failureModule,\n\t\tgroups,\n\t\tnotes,\n\t\t...settings\n\t}\n}\n\n/**\n * Build the agent-facing compact view of a flow. When an `InlineScriptSession`\n * is provided, every rawscript module's `content` is moved into the session\n * and replaced with the placeholder `inline_script.<moduleId>` (preprocessor\n * and failure modules included).","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/flow/editableFlowJson.ts#L391-L427","documentation":"validateEditableFlowJson rejects a failure_module whose id already exists among the flow's module IDs (including the preprocessor, which is added to the id set just before this check). IDs must be globally unique in a flow; duplicates would corrupt module references, so the error is thrown before anything is saved.","triggerScenarios":"Calling validateEditableFlowJson when failureModule.id matches any id in the modules array or the preprocessor_module id, e.g. two modules both id'd 'failure' or reusing 'last_step'.","commonSituations":"LLM emitting failure_module with id 'failure' while a main module already uses that id; copying an existing module into failure_module without changing its id; manual JSON edits merging flows.","solutions":["Set failure_module.id to the reserved special id (SPECIAL_MODULE_IDS.FAILURE, i.e. 'failure') only if not already taken; otherwise pick a unique id","Rename the colliding main-module id instead if references depend on it","Regenerate with unique ids via the copilot tooling"],"exampleFix":"// before\nmodules: [{ id: 'failure', value: {...} }]\nfailure_module: { id: 'failure', ... }\n// after\nmodules: [{ id: 'step1', value: {...} }]\nfailure_module: { id: 'failure', value: { type: 'rawscript', ... } }","handlingStrategy":"validation","validationCode":"const ids = new Set(collectAllFlowModuleIdsFromModules(modules))\nif (preprocessor) ids.add(preprocessor.id)\nif (failure && ids.has(failure.id)) throw new Error('duplicate failure id: ' + failure.id)","typeGuard":"function failureIdIsUnique(modules, preprocessor, failure) {\n  const ids = new Set(collectAllFlowModuleIdsFromModules(modules))\n  if (preprocessor) ids.add(preprocessor.id)\n  return !failure || !ids.has(failure.id)\n}","tryCatchPattern":"try {\n  const editable = validateEditableFlowJson(json)\n} catch (e) {\n  if (e.message.includes('Duplicate module ID found in failure_module')) {\n    delete json.failure_module // or rename the colliding module id\n    return validateEditableFlowJson(json)\n  }\n  throw e\n}","preventionTips":["Reserve the id 'failure' exclusively for the failure module","Assert global id uniqueness (modules + preprocessor + failure) before validating","Regenerate ids when merging or copying flow JSON from another flow"],"tags":["validation","flow","duplicate-id"],"backgroundTag":"duplicate-identifier","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}