{"record":{"id":"236fc44270ac95e1","repo":"nautechsystems/nautilus_trader","slug":"failed-to-persist-pre-sign-verification-e","errorCode":null,"errorMessage":"Failed to persist pre-sign verification: {e}","messagePattern":"Failed to persist pre-sign verification: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":6012,"sourceCode":"                )\n                \",\n            )\n            .bind(assignment.intent_id)\n            .bind(nonce)\n            .bind(decision.read_class)\n            .bind(height_start)\n            .bind(height_end)\n            .bind(assignment.manifest_version)\n            .bind(assignment.manifest_digest)\n            .bind(assignment.provider_ids)\n            .bind(assignment.operator_ids)\n            .bind(assignment.failure_domain_ids)\n            .bind(&decision.normalized_value_digest)\n            .bind(revision)\n            .bind(transition_key)\n            .execute(&mut *transaction)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to persist pre-sign verification: {e}\"))?;\n        }\n\n        let result = sqlx::query(\n            \"\n            UPDATE execution_intent\n            SET nonce = $2, updated_at = NOW()\n            WHERE id = $1\n              AND status = 'prepared'\n              AND active\n              AND (nonce IS NULL OR nonce = $2)\n            \",\n        )\n        .bind(assignment.intent_id)\n        .bind(nonce)\n        .execute(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to assign verified execution nonce: {e}\"))?;\n        anyhow::ensure!(","sourceCodeStart":5994,"sourceCodeEnd":6030,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L5994-L6030","documentation":"Inside the same transaction, each pre-sign verification decision is INSERTed into `execution_verification_decision`. This error wraps any SQLx failure of those INSERTs (constraint violation, type mismatch on bound columns, array binding failures, connection errors). The library throws it because the verified nonce assignment requires durable decision evidence; if evidence cannot be persisted, the nonce must not be assigned and the transaction aborts.","triggerScenarios":"A decision row violating a UNIQUE constraint (duplicate transition_key `pre_sign:{intent_id}:{read_class}:{index}` or (intent_id, nonce) key on re-assignment); provider_ids/operator_ids/failure_domain_ids array elements not matching column types; oversized digests or out-of-i64-range heights; connection loss during the loop.","commonSituations":"Retrying a verified assignment after a partial commit of decisions (unique violation on transition_key); callers passing evidence with different read_class values than a previous attempt; schema drift between the Rust struct and the migration; passing more than the allowed number of decisions for a single transition key space.","solutions":["Read the inner `{e}` for the concrete Postgres error: 23505 means duplicate evidence (make the operation idempotent with ON CONFLICT or skip already-recorded decisions); 22P02/42804 means a binding type mismatch.","Ensure the caller does not replay the same decisions for an intent that already has them persisted; record a batch only once.","Verify provider_ids/operator_ids/failure_domain_ids bind as the exact array types the migration defines.","Check heights fit PostgreSQL BIGINT and digests match the column definition; apply pending migrations if the schema is behind."],"exampleFix":"// before: always inserting, failing on replay\nINSERT INTO execution_verification_decision (...) VALUES (...)\n// after: idempotent insert for replays\nINSERT INTO execution_verification_decision (...) VALUES (...)\nON CONFLICT (intent_id, transition_key) DO NOTHING;","handlingStrategy":"try-catch","validationCode":"// Pre-check that evidence has not already been recorded (avoids unique violations on replay)\nlet existing: i64 = sqlx::query_scalar(\"SELECT count(*) FROM execution_verification_decision WHERE intent_id = $1 AND transition_key LIKE 'pre_sign:%'\")\n    .bind(&assignment.intent_id).fetch_one(pool).await?;\nif existing > 0 { /* decisions already persisted; skip re-insert */ }","typeGuard":null,"tryCatchPattern":"if let Err(e) = db.assign_execution_intent_nonce_verified(&assignment).await {\n    if e.to_string().contains(\"Failed to persist pre-sign verification\") {\n        if e.to_string().contains(\"23505\") { /* duplicate evidence: treat as already recorded */ }\n        else { return Err(e); }\n    } else { return Err(e); }\n}","preventionTips":["Record each pre-sign decision batch exactly once; make inserts idempotent on transition_key.","Keep provider_ids/operator_ids/failure_domain_ids element types aligned with the migration's column types.","Range-check heights and digest lengths before building the assignment.","Keep database migrations in sync with the struct definitions."],"tags":["database","postgres","insert-failed","transaction","sqlx"],"backgroundTag":"database-write-failed","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"}