nautechsystems/nautilus_trader · error · anyhow::Error
Verified nonce assignment requires decision evidence
Error message
Verified nonce assignment requires decision evidence
What it means
assign_execution_intent_nonce_verified performs a cryptographically/independently verified nonce assignment and refuses to persist anything without decision evidence. The anyhow::ensure! at database.rs:5892 rejects an ExecutionNonceAssignment whose decisions slice is empty. Evidence is required so the assignment can be audited and validated against the quorum of decisions.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:5892
.map_err(|e| anyhow::anyhow!("Failed to assign nonce {nonce} to execution intent: {e}"))?;
anyhow::ensure!(
result.rows_affected() == 1,
"Execution intent {intent_id} is not prepared for nonce {nonce}"
);
Ok(())
}
/// Assigns the canonical nonce and its authorizing verification evidence atomically.
///
/// # Errors
///
/// Returns an error if the durable nonce ledger, intent ownership, manifest identity, or
/// evidence is inconsistent, or if persistence fails.
pub(crate) async fn assign_execution_intent_nonce_verified(
&self,
assignment: &ExecutionNonceAssignment<'_>,
) -> anyhow::Result<()> {
anyhow::ensure!(
!assignment.decisions.is_empty(),
"Verified nonce assignment requires decision evidence"
);
anyhow::ensure!(
assignment.provider_ids.len() == 3 && assignment.operator_ids.len() == 3,
"Verified nonce assignment requires exactly three provider and operator IDs"
);
anyhow::ensure!(
assignment.failure_domain_ids.len() >= 3,
"Verified nonce assignment requires the configured failure domains"
);
let chain_id = i32::try_from(assignment.chain_id)
.context("Verification chain ID exceeds PostgreSQL INTEGER")?;
let nonce =
i64::try_from(assignment.nonce).context("Execution nonce exceeds PostgreSQL BIGINT")?;
let mut transaction = self
.pool
.begin()View on GitHub (pinned to 18893faf8b)
Solutions
- Populate assignment.decisions with the collected decision evidence before calling the verified assignment path.
- Fail fast upstream: check decisions.is_empty() (or the evidence collector's result) before constructing the assignment.
- If evidence is genuinely unavailable, use the non-verified assignment path only if policy allows, or abort the nonce assignment.
- Log/inspect why the evidence collector produced zero decisions (provider connectivity, wrong chain_id, misconfigured evidence source).
Example fix
// before
let assignment = ExecutionNonceAssignment { decisions: Vec::new(), .. };
database.assign_execution_intent_nonce_verified(&assignment).await?;
// after
anyhow::ensure!(!decisions.is_empty(), "no decision evidence collected for nonce assignment");
let assignment = ExecutionNonceAssignment { decisions, .. };
database.assign_execution_intent_nonce_verified(&assignment).await?; Defensive patterns
Strategy: validation
Validate before calling
// validate the assignment struct before the verified call
if assignment.decisions.is_empty() {
return Err(anyhow::anyhow!("refusing verified nonce assignment: no decision evidence"));
} Type guard
fn has_decision_evidence(a: &ExecutionNonceAssignment<'_>) -> bool {
!a.decisions.is_empty()
} Try / catch
match database.assign_execution_intent_nonce_verified(&assignment).await {
Err(e) if e.to_string().contains("requires decision evidence") => {
// fall back to re-collecting evidence or abort the round
recollect_evidence_and_retry().await?;
}
Ok(()) => {},
Err(e) => return Err(e),
} Prevention
- Make evidence collection fail loudly instead of returning an empty list.
- Never construct ExecutionNonceAssignment by hand without evidence in production paths.
- Add an assertion/log when the decisions collector yields zero records.
- Keep a unit test covering the empty-decisions rejection.
When it happens
Trigger: Constructing or deserializing an ExecutionNonceAssignment with an empty decisions vector (e.g. all providers failed to return decisions, evidence collection was skipped, or the struct was built by hand in tests/tooling) and passing it to assign_execution_intent_nonce_verified.
Common situations: Upstream evidence collection silently returning zero records instead of failing; a provider outage leading to an empty decision list being passed through; test harnesses constructing minimal assignments without evidence; a refactor changing the decisions field to a default-empty collection.
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
- No symbols provided
- At least one --address or --addresses-file entry is required
- Quote maps must not be empty
- Continuous future `bar_types` request parameter must not be
- Cannot batch modify empty order list
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c0097569b0cccbe3.
Report an issue: GitHub.