nautechsystems/nautilus_trader · error

Verified action requires a decision class and evidence

Error message

Verified action requires a decision class and evidence

What it means

A validation guard thrown when an ExecutionVerificationBatch has an empty (or whitespace-only) decision_class or an empty decisions list. The library refuses to record a verified action without both a decision classification and at least one piece of decision evidence.

Source

Thrown at crates/adapters/blockchain/src/cache/database.rs:6048

        anyhow::ensure!(
            result.rows_affected() == 1,
            "Execution intent {} is not prepared for canonical nonce {}",
            assignment.intent_id,
            assignment.nonce
        );
        transaction
            .commit()
            .await
            .map_err(|e| anyhow::anyhow!("Failed to commit verified nonce assignment: {e}"))?;
        Ok(())
    }

    /// Appends one verified decision batch before an action on an existing active intent.
    pub(crate) async fn record_execution_verification_batch(
        &self,
        batch: &ExecutionVerificationBatch<'_>,
    ) -> anyhow::Result<()> {
        anyhow::ensure!(
            !batch.decision_class.trim().is_empty() && !batch.decisions.is_empty(),
            "Verified action requires a decision class and evidence"
        );
        anyhow::ensure!(
            batch.provider_ids.len() == 3
                && batch.operator_ids.len() == 3
                && batch.failure_domain_ids.len() >= 3,
            "Verified action requires the configured provider identities"
        );
        let chain_id = i32::try_from(batch.chain_id)
            .context("Verification chain ID exceeds PostgreSQL INTEGER")?;
        let nonce =
            i64::try_from(batch.nonce).context("Execution nonce exceeds PostgreSQL BIGINT")?;
        let mut transaction = self
            .pool
            .begin()
            .await
            .map_err(|e| anyhow::anyhow!("Failed to start verified action evidence: {e}"))?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Populate batch.decision_class with the intended classification string before calling record_execution_verification_batch.
  2. Ensure at least one decision entry is present in batch.decisions.
  3. Trim and validate inputs at the batch construction site so empty values fail early with a clearer message.

Example fix

// before
let batch = ExecutionVerificationBatch { decision_class: collected_class.trim().to_string(), decisions: decisions, .. };
// after
anyhow::ensure!(!collected_class.trim().is_empty(), "decision_class required");
anyhow::ensure!(!decisions.is_empty(), "at least one decision required");
let batch = ExecutionVerificationBatch { decision_class: collected_class.trim().to_string(), decisions, .. };
Defensive patterns

Strategy: validation

Validate before calling

// Rust
fn validate_batch_basic(batch: &ExecutionVerificationBatch) -> Result<(), String> {
    if batch.decision_class.trim().is_empty() { return Err("decision_class is empty".into()); }
    if batch.decisions.is_empty() { return Err("decisions is empty".into()); }
    Ok(())
}

Type guard

fn has_evidence(batch: &ExecutionVerificationBatch) -> bool {
    !batch.decision_class.trim().is_empty() && !batch.decisions.is_empty()
}

Prevention

When it happens

Trigger: Calling record_execution_verification_batch with batch.decision_class == ""/whitespace or batch.decisions.is_empty().

Common situations: A caller assembling the batch programmatically forgets to fill in decision_class; an upstream collector produced no decisions but the pipeline still tried to record the batch; string fields populated from trimmed-empty env/config values.

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 nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/6ded942ef20d6064. Report an issue: GitHub.