{"record":{"id":"f5a519c49578df0a","repo":"datahaven-xyz/datahaven","slug":"deferperiodisover","errorCode":"DeferPeriodIsOver","errorMessage":"DeferPeriodIsOver","messagePattern":"DeferPeriodIsOver","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"operator/pallets/external-validator-slashes/src/lib.rs","lineNumber":367,"sourceCode":"        }\n    }\n\n    #[pallet::call]\n    impl<T: Config> Pallet<T> {\n        /// Cancel a slash that was deferred for a later era\n        #[pallet::call_index(0)]\n        #[pallet::weight(T::WeightInfo::cancel_deferred_slash(slash_indices.len() as u32))]\n        pub fn cancel_deferred_slash(\n            origin: OriginFor<T>,\n            era: EraIndex,\n            slash_indices: Vec<u32>,\n        ) -> DispatchResult {\n            ensure_root(origin)?;\n\n            let active_era = T::EraIndexProvider::active_era().index;\n\n            // We need to be in the defer period\n            ensure!(\n                era <= active_era\n                    .saturating_add(T::SlashDeferDuration::get().saturating_add(One::one()))\n                    && era > active_era,\n                Error::<T>::DeferPeriodIsOver\n            );\n\n            ensure!(!slash_indices.is_empty(), Error::<T>::EmptyTargets);\n            ensure!(\n                is_sorted_and_unique(&slash_indices),\n                Error::<T>::NotSortedAndUnique\n            );\n            // fetch slashes for the era in which we want to defer\n            let mut era_slashes = Slashes::<T>::get(era);\n\n            let last_item = slash_indices[slash_indices.len().saturating_sub(1)];\n            ensure!(\n                (last_item as usize) < era_slashes.len(),\n                Error::<T>::InvalidSlashIndex","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/datahaven-xyz/datahaven/blob/edcb13dbbcd3c29489eaa2480a6f60ee4cb1f3ec/operator/pallets/external-validator-slashes/src/lib.rs#L349-L385","documentation":"Thrown by the `cancel_deferred_slash` root extrinsic in `pallet-external-validator-slashes` when the given era is outside the slash defer period. A slash can only be cancelled while `active_era < era <= active_era + SlashDeferDuration + 1`; before or after that window the cancellation is rejected.","triggerScenarios":"Calling `cancel_deferred_slash(origin, era, slash_indices)` with `era <= active_era` (already consumed/visible) or `era > active_era + SlashDeferDuration + 1` (a future slash that is not yet in its defer window).","commonSituations":"Governance/root calling the extrinsic after the defer duration already elapsed, mis-typing the era index, or a misconfigured `SlashDeferDuration` (e.g. 0) making the window too short.","solutions":["Compute the valid window and cancel slashes for an era where `active_era < era <= active_era + SlashDeferDuration + 1`.","Increase `SlashDeferDuration` in the runtime config if the operational window is too short.","Query current `active_era` before invoking and pick the correct era parameter.","If the slash already applied, use the force-inject/refund mechanism instead of cancellation."],"exampleFix":"// before: blind call\ncancel_deferred_slash(origin, era, indices);\n// after: check window first\nlet active = T::EraIndexProvider::active_era().index;\nensure!(era > active && era <= active + defer_duration + 1);\ncancel_deferred_slash(origin, era, indices);","handlingStrategy":"validation","validationCode":"const activeEra = await api.query.staking.activeEra();\nconst defer = await api.consts.externalValidatorSlashes.slashDeferDuration();\nif (!(era > activeEra.index && era <= activeEra.index + defer + 1)) {\n  throw new Error(`era ${era} is outside the defer window`);\n}","typeGuard":"function isWithinDeferWindow(era, activeEra, deferDuration) {\n  return era > activeEra && era <= activeEra + deferDuration + 1;\n}","tryCatchPattern":"try {\n  await api.tx.externalValidatorSlashes.cancelDeferredSlash(era, indices)\n    .signAndSend(rootSigner);\n} catch (e) {\n  if (String(e).includes('DeferPeriodIsOver')) {\n    console.error('Defer window elapsed; use force-inject/refund path instead');\n  }\n}","preventionTips":["Always read activeEra from storage immediately before the call","Set SlashDeferDuration large enough for the operational response window","Automate slash cancellation early in the defer window, not at its end"],"tags":["staking","slashing","substrate","era"],"backgroundTag":"invalid-state-transition","analyzedSha":"edcb13dbbcd3c29489eaa2480a6f60ee4cb1f3ec","analyzedAt":"2026-09-13T19:19:32.206Z","contentChangedAt":"2026-09-13T19:19:32.206Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}