nautechsystems/nautilus_trader · critical

Execution schema version

Error message

Execution schema version {} is newer than supported version {EXECUTION_SCHEMA_VERSION}

What it means

The blockchain adapter's execution cache database stores a schema version; on open, if the on-disk execution schema version is greater than EXECUTION_SCHEMA_VERSION compiled into this binary, opening is aborted. Downgrading the library (running an older binary against a database written by a newer one) would risk misreading or corrupting the schema.

Solutions

  1. Upgrade the library back to the version (or newer) that wrote the database so its schema version is supported
  2. Move/rename the existing cache database file so a fresh one is created at the old schema version (loses cached data)
  3. If the data is dispensable, delete the cache database and let it rebuild from the chain
  4. Check the installed version row in the database to confirm which version created it before deciding

Example fix

// before: opening old binary against migrated DB
let db = ExecutionDatabase::open(path).await?; // bails: schema too new
// after: detect and start fresh
match ExecutionDatabase::open(path).await {
    Ok(db) => db,
    Err(e) if e.to_string().contains("newer than supported") => {
        fs::rename(path, path.with_extension("db.newer-schema"))?;
        ExecutionDatabase::open(path).await?
    }
    Err(e) => return Err(e),
}
Defensive patterns

Strategy: try-catch

Validate before calling

fn is_schema_too_new(err: &anyhow::Error) -> bool {
    err.to_string().contains("newer than supported version")
}
// check before opening: if cache file exists and was written by a newer build, relocate it first

Try / catch

let db = match ExecutionDatabase::open(path).await {
    Ok(db) => db,
    Err(e) if e.to_string().contains("newer than supported version") => {
        warn!("cache written by newer build; recreating at old schema");
        std::fs::rename(&path, path.with_extension("db.incompatible"))?;
        ExecutionDatabase::open(path).await?
    }
    Err(e) => return Err(e.into()),
};

Prevention

When it happens

Trigger: Opening the blockchain execution cache database (database.rs execution open path) after switching from a newer version of nautilus_blockchain back to an older one, so installed_version > EXECUTION_SCHEMA_VERSION.

Common situations: Rolling back a deployment or checking out an older git branch while the SQLite/DB file was migrated by a newer build; sharing one cache file across machines with different library versions; restoring a backup created by newer software.

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/c6693c843e348452. Report an issue: GitHub.

Appendix: source

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

        ] {
            sqlx::query(statement)
                .execute(&mut *transaction)
                .await
                .map_err(|e| {
                    anyhow::anyhow!("Failed to migrate execution_transaction table: {e}")
                })?;
        }

        let installed_version = sqlx::query_scalar::<_, i16>(
            "SELECT version FROM execution_schema_version WHERE component = 'evm_execution'",
        )
        .fetch_optional(&mut *transaction)
        .await
        .map_err(|e| anyhow::anyhow!("Failed to read execution schema version: {e}"))?;
        if let Some(installed_version) = installed_version
            && installed_version > EXECUTION_SCHEMA_VERSION
        {
            anyhow::bail!(
                "Execution schema version {} is newer than supported version {EXECUTION_SCHEMA_VERSION}",
                installed_version
            );
        }

        let unresolved_legacy = sqlx::query_scalar::<_, i64>(
            "
            SELECT COUNT(*)
            FROM execution_transaction
            WHERE status IN ('pending', 'included', 'reverted')
            ",
        )
        .fetch_one(&mut *transaction)
        .await
        .map_err(|e| anyhow::anyhow!("Failed to inspect legacy execution transactions: {e}"))?;
        anyhow::ensure!(
            unresolved_legacy == 0,
            "Cannot safely migrate {unresolved_legacy} unresolved execution schema version 1 transaction(s); resolve them with the prior version before enabling version {EXECUTION_SCHEMA_VERSION}"

View on GitHub (pinned to 18893faf8b)