nautechsystems/nautilus_trader · error · EventStoreError::Backend

catalog marker join plan failed for {data_cls}: {error}

Error message

catalog marker join plan failed for {data_cls}: {error}

What it means

While computing replayable records for a marker join, the event store asks the catalog to produce a slice plan (`plan_slice`). If the catalog backend fails planning, the error is converted via `catalog_error` into `EventStoreError::Backend` with the message 'catalog marker join plan failed for {data_cls}: {error}'. It wraps the underlying backend failure with the data class and action for context.

Source

Thrown at crates/event_store/src/markers/join.rs:168

fn replayable_data_class(data_cls: DataClass) -> Option<&'static str> {
    match data_cls {
        DataClass::Quote => Some("quotes"),
        DataClass::Trade => Some("trades"),
        DataClass::Bar => Some("bars"),
        DataClass::BookDeltas | DataClass::BookDepth10 => None,
    }
}

fn plan_slice<C>(
    catalog: &mut C,
    query: &CatalogSliceQuery,
) -> Result<CatalogSliceCoverage, EventStoreError>
where
    C: ReplayCatalog + ?Sized,
{
    catalog
        .plan_slice(query)
        .map_err(|e| catalog_error(&query.data_cls, "plan", e))
}

fn load_slice<C>(
    catalog: &mut C,
    plan: &CatalogSlicePlan,
) -> Result<Vec<CatalogReplayRecord>, EventStoreError>
where
    C: ReplayCatalog + ?Sized,
{
    catalog
        .load_slice(plan)
        .map_err(|e| catalog_error(&plan.query.data_cls, "load", e))
}

fn catalog_error(data_cls: &str, action: &str, error: impl Display) -> EventStoreError {
    EventStoreError::Backend(format!(
        "catalog marker join {action} failed for {data_cls}: {error}"
    ))

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the wrapped `{error}` in the message to identify the underlying backend cause and fix that first
  2. Validate the `query` (data class, time range) against the catalog's supported classes and ranges before replay
  3. Verify the catalog backend is reachable and its indexes/storage are healthy
  4. Implement `ReplayCatalog::plan_slice` correctly if this is a custom catalog

Example fix

// before: planning failure surfaces mid-replay
let records = store.load_replayable_records(&query)?;
// after: validate query / handle backend error up front
match catalog.plan_slice(&query) {
    Ok(_) => { let records = store.load_replayable_records(&query)?; }
    Err(e) => log::error!("replay planning failed for {}: {e}", query.data_cls),
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check the catalog can plan this query before replay
if let Err(e) = catalog.plan_slice(&query) {
    log::error!("cannot plan replay for {}: {e}", query.data_cls);
    return;
}

Try / catch

match store.load_replayable_records(&query) {
    Err(EventStoreError::Backend(msg)) if msg.contains("plan failed") => {
        eprintln!("catalog planning failed, aborting replay: {msg}");
    }
    Err(e) => return Err(e.into()),
    Ok(records) => process(records),
}

Prevention

When it happens

Trigger: Calling `load_replayable_records` on a catalog whose backend cannot plan the queried slice — malformed query range, unsupported `data_cls`, backend storage error (corrupt index, unavailable store), or a `ReplayCatalog` implementation returning a planning error.

Common situations: Replaying event-store data against a catalog whose backend is down or misconfigured; querying a data class the catalog does not support; range/query parameters invalid for the backend (e.g. inverted start/end).

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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