windmill-labs/windmill · error
Cannot reject module without a beforeFlow snapshot
Error message
Cannot reject module without a beforeFlow snapshot
What it means
rejectModule reverts one module-level change detected by the flow diff manager by restoring it from the `beforeFlow` snapshot taken when the diff session started. If no snapshot was captured (`beforeFlow` is unset) there is nothing to revert to, so it throws 'Cannot reject module without a beforeFlow snapshot'. This is an internal-state precondition: rejecting a diff is meaningless without the baseline.
Source
Thrown at frontend/src/lib/components/flows/flowDiffManager.svelte.ts:315
}
} else if (info.action === 'modified') {
// Modified: Apply modifications to beforeFlow module
const beforeModule = findModuleInFlow(beforeFlow.value, actualId) ?? undefined
const afterModule = findModuleInFlow(currentFlow, actualId) ?? undefined
if (beforeModule && afterModule) {
replaceFlowModule(beforeModule, $state.snapshot(afterModule))
}
}
}
/**
* Reject a module action (revert the changes)
* Removes the action from tracking after rejection
*/
function rejectModule(id: string, flowStore?: StateStore<ExtendedOpenFlow>) {
if (!beforeFlow) {
throw new Error('Cannot reject module without a beforeFlow snapshot')
}
const actualId = id.startsWith(DUPLICATE_MODULE_PREFIX)
? id.substring(DUPLICATE_MODULE_PREFIX.length)
: id
const info = moduleActions[id]
if (!info) return
// Only perform revert operations if flowStore is provided
if (flowStore) {
if (id === SPECIAL_MODULE_IDS.INPUT) {
// Revert input schema changes
flowStore.val.schema = beforeFlow.schema
currentInputSchema = flowStore.val.schema
} else if (info.action === 'added') {
// Added in after: Remove from flowStore (currentFlow)
// deleteModuleFromFlow handles the case where the module was already deleted (e.g., with its parent)View on GitHub (pinned to e474e8803c)
Solutions
- Only create/use the diff manager (and call rejectModule) within a review session that passes the original flow as beforeFlow.
- Disable the reject/reject-all UI when beforeFlow is absent.
- Re-open the review (recompute the diff with a fresh snapshot) if the session was already ended.
- Guard calls: check the manager exposes a snapshot/hasBeforeFlow indicator first.
Example fix
// before rejectAll() // after if (!diffManager.hasBeforeFlow) return diffManager.rejectAll()
Defensive patterns
Strategy: validation
Validate before calling
if (!diffManager.hasBeforeFlow()) return // no snapshot: nothing to reject
Try / catch
try { rejectModule(id) } catch (e) { if ((e as Error).message.includes('beforeFlow')) reopenDiffReview(); else throw e } Prevention
- Instantiate the diff manager only within a review session that supplies the original flow.
- Disable reject/reject-all controls once the snapshot is consumed or the session ends.
When it happens
Trigger: Calling rejectModule(id, flowStore?) — directly or via rejectAll — on a flowDiffManager instance created without a beforeFlow snapshot (e.g. manager instantiated outside a diff-review session, snapshot cleared after accept-all/reset, or reject invoked after the review session ended).
Common situations: UI still showing the diff panel after the snapshot was consumed/reset; calling rejectModule on a manager instance that was never initialized with the original flow; race where the review session is torn down while a reject request is in flight.
Related errors
- Failed to start test run - testFlow returned undefined
- No flow available to test step from. Please ensure you have
- Node ${moduleId} not found
- Can only fork a script module
- Draft diff not supported for kind ${kind}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/e8630ca12671e0f3.
Report an issue: GitHub.