nautechsystems/nautilus_trader · warning

API key is valid UTF-8

Error message

API key is valid UTF-8

What it means

DatabentoApiKey::api_key() returns the key as &str; the key is stored as raw bytes and this accessor converts with str::from_utf8, expecting success. The invariant holds because the key is only ever constructed from a String (valid UTF-8), so the panic indicates the byte storage was corrupted or built through a non-validating path.

Source

Thrown at crates/adapters/databento/src/common.rs:96

    /// Creates a new [`Credential`] instance from the API key.
    #[must_use]
    pub fn new(api_key: impl Into<String>) -> Self {
        let api_key_bytes = api_key.into().into_bytes();

        Self {
            api_key: api_key_bytes.into_boxed_slice(),
        }
    }

    /// Returns the API key associated with this credential.
    ///
    /// # Panics
    ///
    /// This method should never panic as the API key is always valid UTF-8,
    /// having been created from a String.
    #[must_use]
    pub fn api_key(&self) -> &str {
        std::str::from_utf8(&self.api_key).expect("API key is valid UTF-8")
    }

    /// Returns a masked version of the API key for logging purposes.
    ///
    /// Shows first 4 and last 4 characters with ellipsis in between.
    /// For keys shorter than 8 characters, shows asterisks only.
    #[must_use]
    pub fn api_key_masked(&self) -> String {
        nautilus_core::string::secret::mask_api_key(self.api_key())
    }
}

/// # Errors
///
/// Returns an error if converting `start` or `end` to `OffsetDateTime` fails.
pub fn get_date_time_range(start: UnixNanos, end: UnixNanos) -> anyhow::Result<DateTimeRange> {
    Ok(DateTimeRange::from((
        OffsetDateTime::from_unix_timestamp_nanos(i128::from(start.as_u64()))?,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Construct DatabentoApiKey only via its String/&str-based API so UTF-8 is validated at the boundary.
  2. If loading from raw bytes, validate with String::from_utf8 first and surface a proper error.
  3. Report a bug if this fires with stock constructors — it indicates memory corruption or an unsafe path.

Example fix

// before
let key = DatabentoApiKey::from_raw_bytes(untrusted); // may violate UTF-8 invariant
// after
let s = String::from_utf8(untrusted).map_err(|e| Error::InvalidApiKey(e))?;
let key = DatabentoApiKey::new(s);
Defensive patterns

Strategy: validation

Validate before calling

let key_str = String::from_utf8(raw_key_bytes)
    .map_err(|e| anyhow!("Databento API key is not UTF-8: {e}"))?;
let key = DatabentoApiKey::new(key_str);

Type guard

fn is_valid_api_key(bytes: &[u8]) -> bool { std::str::from_utf8(bytes).is_ok() }

Prevention

When it happens

Trigger: In practice unreachable when using the documented constructor from String; could only fire if the api_key bytes were written via unsafe code or loaded from a non-UTF-8 source without validation.

Common situations: Custom deserialization (e.g. reading the key from a file or env as raw bytes) that bypasses the String-based constructor is the realistic way this invariant would be broken.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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