nautechsystems/nautilus_trader · error · anyhow::Error

No durable store configured; refusing to submit a transactio

Error message

No durable store configured; refusing to submit a transaction

What it means

BlockchainExecutionClient::transaction_executor (crates/adapters/blockchain/src/execution/client.rs:792) builds the shared TransactionExecutor and fails closed when self.cache.database is None - there is no durable store, so submitting, wrapping, or approving is refused. connect() attaches a Postgres store only when BlockchainExecutionClientConfig::postgres_cache_database_config is set, logging "No Postgres cache database configured; transactions will be refused (no durable store)" otherwise; the first transaction attempt then hits this error. Durable persistence of intents is a prerequisite for crash-safe execution, hence the refusal rather than a best-effort submit.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:792

            })?;

        if pool.token0.get_token_priority() == pool.token1.get_token_priority() {
            anyhow::bail!(
                "Pool {instrument_id} tokens share a token priority; base and quote orientation is ambiguous"
            );
        }

        Ok(pool)
    }

    /// Builds the shared transaction executor from the connected client state.
    ///
    /// # Errors
    ///
    /// Returns an error if no durable store is configured or the signer is not initialized.
    fn transaction_executor(&self) -> anyhow::Result<TransactionExecutor> {
        let database = self.cache.database.clone().ok_or_else(|| {
            anyhow::anyhow!("No durable store configured; refusing to submit a transaction")
        })?;
        let signer = self
            .signer
            .clone()
            .ok_or_else(|| anyhow::anyhow!("Signer not initialized; connect the client first"))?;

        Ok(TransactionExecutor {
            http_rpc_client: self.http_rpc_client.clone(),
            database,
            signer,
            in_flight: Arc::clone(&self.in_flight),
            wallet_balance: Arc::clone(&self.wallet_balance),
            account_id: self.core.account_id,
            wallet_address: self.wallet_address,
            chain_id: self.chain.chain_id,
            max_fee_per_gas_wei: self.config.max_fee_per_gas_wei,
            base_fee_buffer_bps: self.config.base_fee_buffer_bps,
            gas_limit: self.config.gas_limit,

View on GitHub (pinned to 2114cf6f76)

Solutions

  1. Set postgres_cache_database_config on BlockchainExecutionClientConfig with valid PostgresConnectOptions before building the client.
  2. Ensure connect() is called and returns Ok; it attaches the store and runs ensure_execution_transaction_schema.
  3. Check connect-time logs for "Failed to connect to the Postgres cache database" and fix credentials/host/port.
  4. Guard startup: refuse to trade when client.cache.has_database() is false.

Example fix

// before
let config = BlockchainExecutionClientConfig {
    postgres_cache_database_config: None, // no durable store
    ..Default::default()
};
// connect() warns; first submit_order fails: "No durable store configured; refusing to submit a transaction"

// after
let config = BlockchainExecutionClientConfig {
    postgres_cache_database_config: Some(postgres_connect_options),
    ..Default::default()
};
Defensive patterns

Strategy: validation

Validate before calling

// Rust: fail fast at startup when no durable store is attached
anyhow::ensure!(
    client.cache.has_database(),
    "execution client requires postgres_cache_database_config; refusing to start"
);

Type guard

fn is_no_durable_store(e: &anyhow::Error) -> bool {
    e.to_string().contains("No durable store configured; refusing to submit a transaction")
}

Try / catch

match client.wrap(amount_wei).await {
    Ok(hash) => hash,
    Err(e) if is_no_durable_store(&e) => {
        // configuration defect - stop trading rather than retry
        return Err(e.context("set postgres_cache_database_config and reconnect"));
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: BlockchainExecutionClientConfig built with postgres_cache_database_config: None and then wrap/approve/submit_order called; Postgres options present but connect() never invoked (or it failed at the Postgres step), leaving the cache without a store; a typo in the Postgres env vars making the config parser leave the field None.

Common situations: Missing POSTGRES_* environment variables in the deployment; a config file where the database section is commented out; swapping a production config for a local dev config that omits persistence.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21). Data as JSON: /api/errors/fa802a85783e9ed5. Report an issue: GitHub.