nautechsystems/nautilus_trader · error · anyhow::Error

Failed to load custom data: {e}

Error message

Failed to load custom data: {e}

What it means

Raised by `load_custom_data` when the SELECT used to fetch `custom` rows for the requested data type fails. The query builder has several branches (with/without metadata and identifier filters); any sqlx fetch failure across them is wrapped with this message.

Source

Thrown at crates/infrastructure/src/sql/queries.rs:1722

                .fetch_all(pool)
                .await
            }
            None => {
                sqlx::query(
                    r#"SELECT value, ts_event, ts_init FROM "custom"
                   WHERE (data_type = $1 OR data_type = $2)
                     AND metadata = $3
                     AND identifier = ''
                   ORDER BY ts_init ASC"#,
                )
                .bind(type_name)
                .bind(short_type)
                .bind(&metadata_json)
                .fetch_all(pool)
                .await
            }
        }
        .map_err(|e| anyhow::anyhow!("Failed to load custom data: {e}"))?;

        let mut results = Vec::with_capacity(rows.len());
        for row in rows {
            let value_json: serde_json::Value = row.try_get("value")?;
            let json_bytes = serde_json::to_vec(&value_json)
                .map_err(|e| anyhow::anyhow!("Failed to serialize JSON: {e}"))?;
            let custom =
                CustomData::from_json_bytes(&json_bytes).map_err(|e| anyhow::anyhow!("{e}"))?;
            results.push(custom);
        }
        Ok(results)
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the wrapped sqlx error message for the exact failure.
  2. Run migrations so the `custom` table exists with value/data_type/metadata/identifier columns.
  3. Ensure the metadata argument matches the JSON format stored when inserting (serde_json string).
  4. Retry transient failures; validate pool connectivity.
Defensive patterns

Strategy: retry

Validate before calling

let exists: bool = sqlx::query_scalar(
    "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'custom')")
    .fetch_one(pool).await?;
anyhow::ensure!(exists, "custom table missing; run migrations");
// metadata must be a valid JSON string matching stored format
if let Some(m) = &metadata { serde_json::from_str::<serde_json::Value>(m)?; }

Try / catch

let rows = retry_backoff(3, || load_custom_data(&pool, data_type.clone(), metadata.clone(), identifier.clone())).await
    .map_err(|e| e.context("custom data load failed after retries"))?;

Prevention

When it happens

Trigger: Calling `load_custom_data(pool, data_type, ...)` when the `custom` table is missing, the metadata_json binding is malformed for the comparison used, the pool connection fails, or schema columns don't match the query.

Common situations: Migrations not applied; passing metadata that doesn't match the JSONB column format expected by the query; wrong database; transient PostgreSQL restarts.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


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