nautechsystems/nautilus_trader · critical · anyhow::Error

Execution payload protection version {version} is newer than

Error message

Execution payload protection version {version} is newer than supported version {EXECUTION_PAYLOAD_PROTOCOL_VERSION}

What it means

A guard in `ensure_execution_payload_storage`: the database already has an execution payload protection marker whose protocol version differs from the version this binary supports (EXECUTION_PAYLOAD_PROTOCOL_VERSION). Because the stored version is newer than (or simply not equal to) what this build understands, the node refuses to proceed rather than corrupting protected signed-transaction storage.

Source

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

        .await
        .map_err(|e| anyhow::anyhow!("Failed to activate verification schema: {e}"))?;

        transaction
            .commit()
            .await
            .map_err(|e| anyhow::anyhow!("Failed to commit verification migration: {e}"))?;
        Ok(())
    }

    /// Activates or resumes protected signed-transaction storage for this database.
    pub(crate) async fn ensure_execution_payload_storage(
        &self,
        keys: &PayloadKeySet,
    ) -> anyhow::Result<()> {
        let marker = self.execution_payload_marker().await?;
        match marker {
            None => self.activate_execution_payload_storage(keys).await?,
            Some(version) => anyhow::ensure!(
                version == EXECUTION_PAYLOAD_PROTOCOL_VERSION,
                "Execution payload protection version {version} is newer than supported version {EXECUTION_PAYLOAD_PROTOCOL_VERSION}"
            ),
        }

        loop {
            let state = self.execution_payload_state().await?.ok_or_else(|| {
                anyhow::anyhow!("Execution payload marker exists without durable state")
            })?;
            validate_execution_payload_state(&state, keys)?;
            match state.operation.as_str() {
                "migrate" => {
                    if self
                        .migrate_execution_payload_batch(keys, EXECUTION_PAYLOAD_BATCH_SIZE)
                        .await?
                    {
                        break;
                    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Upgrade to the release whose EXECUTION_PAYLOAD_PROTOCOL_VERSION matches the stored marker version
  2. Check the stored version: SELECT version FROM execution_schema_version WHERE component = '<payload component>'
  3. If a downgrade is truly required, restore a database backup taken with the old version — do not hand-edit the marker
  4. Confirm you are pointing at the intended database (env/config DATABASE_URL)

Example fix

// before: old binary against upgraded DB
let db = Database::connect(config.postgres_url.as_str()).await?; // panics/errors: version mismatch
// after: pin binary version compatible with the DB, or verify first
let stored: i16 = sqlx::query_scalar(
    "SELECT version FROM execution_schema_version WHERE component = $1")
    .bind(EXECUTION_PAYLOAD_COMPONENT).fetch_one(&pool).await?;
assert_eq!(stored, EXECUTION_PAYLOAD_PROTOCOL_VERSION, "update the node binary");
Defensive patterns

Strategy: validation

Validate before calling

let stored: Option<i16> = sqlx::query_scalar(
    "SELECT version FROM execution_schema_version WHERE component = $1")
    .bind(EXECUTION_PAYLOAD_COMPONENT).fetch_optional(&pool).await?;
if let Some(v) = stored {
    assert_eq!(v, EXECUTION_PAYLOAD_PROTOCOL_VERSION,
        "DB payload protocol {} incompatible with binary {}; update the node",
        v, EXECUTION_PAYLOAD_PROTOCOL_VERSION);
}

Type guard

fn is_compatible_protocol(stored: Option<i16>, supported: i16) -> bool {
    matches!(stored, None | Some(v) if v == supported)
}

Try / catch

match ensure_execution_payload_storage(&db, &keys).await {
    Err(e) if e.to_string().contains("newer than supported version") => {
        eprintln!("DB was upgraded by a newer release; upgrade this node binary before connecting");
        std::process::exit(78); // EX_CONFIG
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `ensure_execution_payload_storage` when `execution_payload_marker()` returns Some(version) and version != EXECUTION_PAYLOAD_PROTOCOL_VERSION — i.e. the database was initialized by a newer release with a bumped payload protection protocol and you then started an older binary against the same DB.

Common situations: Downgrade: running a previous release after a newer one upgraded the storage protocol; pointing a test/staging build at a production database initialized by a newer version; hot-swap between builds with different protocol constants.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/470399c34068bde0. Report an issue: GitHub.