datahaven-xyz/datahaven · error · Error

DeferPeriodIsOver

DeferPeriodIsOver

Error message

DeferPeriodIsOver

What it means

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.

Solutions

  1. Compute the valid window and cancel slashes for an era where `active_era < era <= active_era + SlashDeferDuration + 1`.
  2. Increase `SlashDeferDuration` in the runtime config if the operational window is too short.
  3. Query current `active_era` before invoking and pick the correct era parameter.
  4. If the slash already applied, use the force-inject/refund mechanism instead of cancellation.

Example fix

// before: blind call
cancel_deferred_slash(origin, era, indices);
// after: check window first
let active = T::EraIndexProvider::active_era().index;
ensure!(era > active && era <= active + defer_duration + 1);
cancel_deferred_slash(origin, era, indices);
Defensive patterns

Strategy: validation

Validate before calling

const activeEra = await api.query.staking.activeEra();
const defer = await api.consts.externalValidatorSlashes.slashDeferDuration();
if (!(era > activeEra.index && era <= activeEra.index + defer + 1)) {
  throw new Error(`era ${era} is outside the defer window`);
}

Type guard

function isWithinDeferWindow(era, activeEra, deferDuration) {
  return era > activeEra && era <= activeEra + deferDuration + 1;
}

Try / catch

try {
  await api.tx.externalValidatorSlashes.cancelDeferredSlash(era, indices)
    .signAndSend(rootSigner);
} catch (e) {
  if (String(e).includes('DeferPeriodIsOver')) {
    console.error('Defer window elapsed; use force-inject/refund path instead');
  }
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of datahaven-xyz/datahaven@edcb13dbbc (2026-09-13). Data as JSON: /api/errors/f5a519c49578df0a. Report an issue: GitHub.

Appendix: source

Thrown at operator/pallets/external-validator-slashes/src/lib.rs:367

        }
    }

    #[pallet::call]
    impl<T: Config> Pallet<T> {
        /// Cancel a slash that was deferred for a later era
        #[pallet::call_index(0)]
        #[pallet::weight(T::WeightInfo::cancel_deferred_slash(slash_indices.len() as u32))]
        pub fn cancel_deferred_slash(
            origin: OriginFor<T>,
            era: EraIndex,
            slash_indices: Vec<u32>,
        ) -> DispatchResult {
            ensure_root(origin)?;

            let active_era = T::EraIndexProvider::active_era().index;

            // We need to be in the defer period
            ensure!(
                era <= active_era
                    .saturating_add(T::SlashDeferDuration::get().saturating_add(One::one()))
                    && era > active_era,
                Error::<T>::DeferPeriodIsOver
            );

            ensure!(!slash_indices.is_empty(), Error::<T>::EmptyTargets);
            ensure!(
                is_sorted_and_unique(&slash_indices),
                Error::<T>::NotSortedAndUnique
            );
            // fetch slashes for the era in which we want to defer
            let mut era_slashes = Slashes::<T>::get(era);

            let last_item = slash_indices[slash_indices.len().saturating_sub(1)];
            ensure!(
                (last_item as usize) < era_slashes.len(),
                Error::<T>::InvalidSlashIndex

View on GitHub (pinned to edcb13dbbc)