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
- Construct DatabentoApiKey only via its String/&str-based API so UTF-8 is validated at the boundary.
- If loading from raw bytes, validate with String::from_utf8 first and surface a proper error.
- 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
- Build the key only from String/&str sources (env vars, config strings).
- Validate UTF-8 at the boundary when loading raw bytes from files or network.
- Never write into the key's internal byte storage directly.
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
- 16 lowercase hex bytes are valid TradeId
- Close command should not be drained
- Flush command should not be drained
- Order invariant violated: first event must be OrderInitializ
- Chunk should have at least one element to encode
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3c7a2953aa254b85.
Report an issue: GitHub.