{"record":{"id":"6ded942ef20d6064","repo":"nautechsystems/nautilus_trader","slug":"verified-action-requires-a-decision-class-and-evid","errorCode":null,"errorMessage":"Verified action requires a decision class and evidence","messagePattern":"Verified action requires a decision class and evidence","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":6048,"sourceCode":"        anyhow::ensure!(\n            result.rows_affected() == 1,\n            \"Execution intent {} is not prepared for canonical nonce {}\",\n            assignment.intent_id,\n            assignment.nonce\n        );\n        transaction\n            .commit()\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to commit verified nonce assignment: {e}\"))?;\n        Ok(())\n    }\n\n    /// Appends one verified decision batch before an action on an existing active intent.\n    pub(crate) async fn record_execution_verification_batch(\n        &self,\n        batch: &ExecutionVerificationBatch<'_>,\n    ) -> anyhow::Result<()> {\n        anyhow::ensure!(\n            !batch.decision_class.trim().is_empty() && !batch.decisions.is_empty(),\n            \"Verified action requires a decision class and evidence\"\n        );\n        anyhow::ensure!(\n            batch.provider_ids.len() == 3\n                && batch.operator_ids.len() == 3\n                && batch.failure_domain_ids.len() >= 3,\n            \"Verified action requires the configured provider identities\"\n        );\n        let chain_id = i32::try_from(batch.chain_id)\n            .context(\"Verification chain ID exceeds PostgreSQL INTEGER\")?;\n        let nonce =\n            i64::try_from(batch.nonce).context(\"Execution nonce exceeds PostgreSQL BIGINT\")?;\n        let mut transaction = self\n            .pool\n            .begin()\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to start verified action evidence: {e}\"))?;","sourceCodeStart":6030,"sourceCodeEnd":6066,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L6030-L6066","documentation":"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.","triggerScenarios":"Calling record_execution_verification_batch with batch.decision_class == \"\"/whitespace or batch.decisions.is_empty().","commonSituations":"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.","solutions":["Populate batch.decision_class with the intended classification string before calling record_execution_verification_batch.","Ensure at least one decision entry is present in batch.decisions.","Trim and validate inputs at the batch construction site so empty values fail early with a clearer message."],"exampleFix":"// before\nlet batch = ExecutionVerificationBatch { decision_class: collected_class.trim().to_string(), decisions: decisions, .. };\n// after\nanyhow::ensure!(!collected_class.trim().is_empty(), \"decision_class required\");\nanyhow::ensure!(!decisions.is_empty(), \"at least one decision required\");\nlet batch = ExecutionVerificationBatch { decision_class: collected_class.trim().to_string(), decisions, .. };","handlingStrategy":"validation","validationCode":"// Rust\nfn validate_batch_basic(batch: &ExecutionVerificationBatch) -> Result<(), String> {\n    if batch.decision_class.trim().is_empty() { return Err(\"decision_class is empty\".into()); }\n    if batch.decisions.is_empty() { return Err(\"decisions is empty\".into()); }\n    Ok(())\n}","typeGuard":"fn has_evidence(batch: &ExecutionVerificationBatch) -> bool {\n    !batch.decision_class.trim().is_empty() && !batch.decisions.is_empty()\n}","tryCatchPattern":null,"preventionTips":["Construct batches through a builder that rejects empty fields.","Unit-test batch assembly with empty-input cases.","Trim config/env-sourced strings at load time."],"tags":["validation","empty-input","rust"],"backgroundTag":"empty-required-field","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}