datahaven-xyz/datahaven · warning · Error

EmptyTargets

EmptyTargets

Error message

EmptyTargets

What it means

Sentinel dispatch error returned by cancel_deferred_slash when the caller supplies an empty slash_indices vector: there are no deferred slash entries to look up and cancel, so the extrinsic refuses to proceed rather than performing a no-op root call. The input at fault is the slash_indices argument, which must contain at least one valid index into the deferred slash report for the given era.

Solutions

  1. Check `slash_indices` length and skip the extrinsic call when it is empty.
  2. Fix the off-chain query producing indices so it selects the intended deferred slashes.
  3. If all slashes were already cancelled, treat this as a no-op instead of submitting the transaction.

Example fix

// before
cancel_deferred_slash(origin, era, indices);
// after
if !indices.is_empty() {
    cancel_deferred_slash(origin, era, indices);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!slashIndices.length) {
  return; // nothing to cancel, skip transaction
}

Type guard

function hasSlashIndices(indices) {
  return Array.isArray(indices) && indices.length > 0;
}

Try / catch

try {
  await cancelDeferredSlash(era, indices);
} catch (e) {
  if (String(e).includes('EmptyTargets')) {
    console.warn('No slashes to cancel; treating as no-op');
  }
}

Prevention

When it happens

Trigger: Calling `cancel_deferred_slash(origin, era, vec![])` — typically from an off-chain automation that collected no matching slash indices, or a UI passing an unfiltered empty selection.

Common situations: Batch scripts canceling slashes computed by a query that returned no rows, or a governance proposal generated from stale data where all slashes were already cancelled.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

        #[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
            );

            // Remove elements starting from the highest index to avoid shifting issues.
            for index in slash_indices.into_iter().rev() {
                era_slashes.remove(index as usize);
            }
            // insert back slashes

View on GitHub (pinned to edcb13dbbc)