nautechsystems/nautilus_trader · error · anyhow::Error

metadata['user'] must not contain surrounding whitespace

Error message

metadata['user'] must not contain surrounding whitespace

What it means

The `custom_user` helper extracts `metadata['user']` from instrument definition params and rejects values with leading or trailing whitespace via `anyhow::ensure!`. The adapter treats whitespace-padded user strings as invalid configuration rather than silently trimming, because the value is used as an exact identifier. It prevents subtly wrong user attribution in Hyperliquid instrument metadata.

Source

Thrown at crates/adapters/hyperliquid/src/data.rs:367

        };

        let instrument_id = InstrumentId::from_str(raw_instrument_id)
            .with_context(|| format!("invalid instrument_id metadata `{raw_instrument_id}`"))?;

        Ok(Some(instrument_id))
    }

    fn custom_user(data_type: &DataType) -> anyhow::Result<Option<String>> {
        let Some(user) = data_type
            .metadata()
            .and_then(|m| m.get("user"))
            .and_then(|v| v.as_str())
            .filter(|value| !value.is_empty())
        else {
            return Ok(None);
        };

        anyhow::ensure!(
            user == user.trim(),
            "metadata['user'] must not contain surrounding whitespace",
        );

        Ok(Some(user.to_string()))
    }

    async fn bootstrap_instruments(&self) -> anyhow::Result<Vec<InstrumentAny>> {
        let instruments = self
            .http_client
            .request_instruments()
            .await
            .context("failed to fetch instruments during bootstrap")?;

        self.instruments.rcu(|m| {
            for instrument in &instruments {
                m.insert(instrument.id(), instrument.clone());
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Trim the value before passing it: pass `user.trim()` in your config or builder call.
  2. Fix the source config file so the quoted string has no padding.
  3. If generated programmatically, sanitize at the point of construction.

Example fix

// before
let user = Some(" 0xabc123 ".to_string());
// after
let user = Some(" 0xabc123 ".trim().to_string());
Defensive patterns

Strategy: validation

Validate before calling

fn validate_custom_user(user: &str) -> Result<(), String> {
    if user.trim() != user {
        return Err(format!("metadata['user'] has surrounding whitespace: {user:?}"));
    }
    if user.is_empty() {
        return Err("metadata['user'] is empty".into());
    }
    Ok(())
}

Prevention

When it happens

Trigger: Providing an instrument definition/config parameter `metadata.user` (or equivalent custom user field) such as " 0xabc... " or "my-user\n" when building the data client or parsing instrument definitions.

Common situations: Copying a user/address from a document or terminal with trailing spaces; YAML/JSON config with accidentally indented quoted values; templated config emitting newlines.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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