nautechsystems/nautilus_trader · error

Failed to insert into signal table: {e}

Error message

Failed to insert into signal table: {e}

What it means

Raised by `add_signal` when the INSERT into the `signal` table fails. The sqlx execute error is converted into an anyhow::Error with this message, so any database-level constraint violation, type mismatch, or connectivity problem surfaces here.

Source

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

                name, value, ts_event, ts_init, created_at, updated_at
            ) VALUES (
                $1, $2, $3, $4, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
            )
            ON CONFLICT (id)
            DO UPDATE
            SET
                name = $1, value = $2, ts_event = $3, ts_init = $4,
                updated_at = CURRENT_TIMESTAMP
        "#,
        )
        .bind(signal.name.to_string())
        .bind(signal.value.clone())
        .bind(signal.ts_event.to_string())
        .bind(signal.ts_init.to_string())
        .execute(pool)
        .await
        .map(|_| ())
        .map_err(|e| anyhow::anyhow!("Failed to insert into signal table: {e}"))
    }

    /// Loads all `Signal` entries by `name` via the provided `pool`.
    ///
    /// # Errors
    ///
    /// Returns an error if the SQL SELECT or deserialization fails.
    pub async fn load_signals(pool: &PgPool, name: &str) -> anyhow::Result<Vec<Signal>> {
        sqlx::query_as::<_, SignalRow>(
            r#"SELECT * FROM "signal" WHERE name = $1 ORDER BY ts_init ASC"#,
        )
        .bind(name)
        .fetch_all(pool)
        .await
        .map(|rows| rows.into_iter().map(|row| row.0).collect())
        .map_err(|e| anyhow::anyhow!("Failed to load signals: {e}"))
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the embedded sqlx error to identify constraint/table issues.
  2. Run the library's SQL migrations to ensure the `signal` table exists with expected columns.
  3. Validate the signal fields (name, value, ts_event, ts_init) are non-null before insert.
  4. Check the database is writable and the pool connection is healthy.

Example fix

// before
add_signal(&pool, &signal).await?;
// after
if signal.name.is_empty() { anyhow::bail!("signal name required"); }
add_signal(&pool, &signal).await
    .map_err(|e| e.context(format!("adding signal {}", signal.name)))?;
Defensive patterns

Strategy: try-catch

Validate before calling

let exists: bool = sqlx::query_scalar(
    "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'signal')")
    .fetch_one(pool).await?;
anyhow::ensure!(exists, "signal table missing; run migrations");
anyhow::ensure!(!signal.name.is_empty(), "signal name required");

Try / catch

if let Err(e) = add_signal(&pool, &signal).await {
    tracing::error!("signal insert failed: {e:#}");
    return Err(e.context("signal persistence failed"));
}

Prevention

When it happens

Trigger: Calling `add_signal(pool, signal)` when the `signal` table is missing, a NOT NULL/constraint is violated, the pool is dead, or a serialization of bound values (name, value, timestamps as strings) is rejected by PostgreSQL.

Common situations: Schema drift after upgrading the library without rerunning migrations; writing signals with null name/value; database in read-only mode; connection dropped mid-write.

Related errors


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