nautechsystems/nautilus_trader · error

load_synthetic not implemented for PostgreSQL cache adapter:

Error message

load_synthetic not implemented for PostgreSQL cache adapter: {instrument_id}

What it means

The PostgreSQL cache adapter has not implemented load_synthetic; the method unconditionally fails with the instrument id embedded in the message. The SQL backend stores some cache entities but synthetic instrument definitions are not (yet) persisted there.

Source

Thrown at crates/infrastructure/src/sql/cache.rs:806

                        log::error!("Failed to send instrument {instrument_id}: {e:?}");
                    }
                }
                Err(e) => {
                    log::error!("Failed to load instrument {instrument_id}: {e:?}");
                    if let Err(e) = tx.send(None) {
                        log::error!("Failed to send None for instrument {instrument_id}: {e:?}");
                    }
                }
            }
        });
        Ok(rx.recv()?)
    }

    async fn load_synthetic(
        &self,
        instrument_id: &InstrumentId,
    ) -> anyhow::Result<Option<SyntheticInstrument>> {
        anyhow::bail!(
            "load_synthetic not implemented for PostgreSQL cache adapter: {instrument_id}"
        )
    }

    async fn load_account(&self, account_id: &AccountId) -> anyhow::Result<Option<AccountAny>> {
        let pool = self.pool.clone();
        let account_id = account_id.to_owned();
        let (tx, rx) = std::sync::mpsc::channel();

        tokio::spawn(async move {
            let result = DatabaseQueries::load_account(&pool, &account_id).await;
            match result {
                Ok(account) => {
                    if let Err(e) = tx.send(account) {
                        log::error!("Failed to send account {account_id}: {e:?}");
                    }
                }
                Err(e) => {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Do not rely on the cache database for synthetic instruments: construct/load them from the config or local cache instead of via the SQL adapter
  2. Use the Redis cache adapter if synthetics must be persisted to a backing database
  3. Implement load_synthetic in crates/infrastructure/src/sql/cache.rs, persisting synthetic definitions like other instruments

Example fix

// before
let synthetic = cache_db.load_synthetic(&synthetic_id)?; // bails on Postgres
// after
let synthetic = cache.synthetic(&synthetic_id) // resolve from in-memory cache/config
    .ok_or_else(|| anyhow::anyhow!("synthetic {synthetic_id} not configured"))?;
Defensive patterns

Strategy: fallback

Validate before calling

// check adapter capability before calling
fn supports_synthetic_load(db: &dyn CacheDatabase) -> bool { db.as_any().downcast_ref::<PostgresCache>().is_none() }

Try / catch

match cache_db.load_synthetic(&synthetic_id) {
    Ok(s) => s,
    Err(e) if e.to_string().contains("not implemented") => load_synthetic_from_config(&synthetic_id),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Configuring a CacheDatabase with the PostgreSQL adapter and requesting a synthetic instrument via cache.load_synthetic — e.g. a strategy that looks up its synthetic instruments from the cache database on start.

Common situations: Migrating a deployment from Redis cache to PostgreSQL cache; strategies using SyntheticInstrument that worked with the Redis adapter; enabling the SQL adapter for a trading config that references synthetics.

Related errors


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