nautechsystems/nautilus_trader · error · anyhow::Error
Certificate path is not a directory: {}
Error message
Certificate path is not a directory: {} What it means
create_tls_config_from_certs_dir expects certs_dir to be a directory containing certificate/key PEM files. If the path is not a directory (missing path, or a file passed instead), it bails with this error before scanning certificates.
Source
Thrown at crates/network/src/tls.rs:97
match request.uri().host() {
// rustls expects IPv6 addresses without the surrounding [] brackets
Some(d) if d.starts_with('[') && d.ends_with(']') => Ok(d[1..d.len() - 1].to_string()),
Some(d) => Ok(d.to_string()),
None => Err(Error::Io(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Request URI missing host component",
))),
}
}
pub(crate) fn create_tls_config_from_certs_dir(
certs_dir: &Path,
require_client_auth: bool,
) -> anyhow::Result<rustls::ClientConfig> {
install_cryptographic_provider();
if !certs_dir.is_dir() {
anyhow::bail!(
"Certificate path is not a directory: {}",
certs_dir.display()
);
}
let mut all_certs: Vec<(std::path::PathBuf, Vec<CertificateDer<'static>>)> = Vec::new();
let mut client_key = None;
let mut root_store = rustls::RootCertStore::empty();
root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
// Sort entries for deterministic cert/key selection across platforms
let mut entries: Vec<_> = std::fs::read_dir(certs_dir)?.collect::<Result<Vec<_>, _>>()?;
entries.sort_by_key(std::fs::DirEntry::path);
for entry in entries {
let path = entry.path();
if client_key.is_none()View on GitHub (pinned to 18893faf8b)
Solutions
- Point the config at the directory that contains the PEM certs/keys, not a file inside it.
- Verify the path exists and is a directory at startup (certs_dir.is_dir()).
- Check volume mounts / file deployment so the certs directory is present in the runtime environment.
- Use absolute paths for cert directories to avoid working-directory surprises.
Example fix
// before tls_certs_dir: "/etc/certs/ca.pem", // after tls_certs_dir: "/etc/certs", // directory containing ca.pem, client.pem, client.key
Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate TLS certs path at startup
let certs_dir = std::path::Path::new(&cfg.tls_certs_dir);
if !certs_dir.is_dir() {
return Err(anyhow::anyhow!("tls_certs_dir must be a directory: {}", certs_dir.display()));
} Type guard
fn is_certs_dir(p: &std::path::Path) -> bool { p.is_dir() } Try / catch
let tls_cfg = create_tls_config_from_certs_dir(certs_dir, require_client_auth)
.map_err(|e| { log::error!("tls config failed: {e}"); e })?; Prevention
- Point config at the directory, not a file within it.
- Use absolute paths for cert locations.
- Verify cert volumes are mounted in deployments.
- Check path validity in a startup self-check.
When it happens
Trigger: Calling create_tls_config_from_certs_dir (from connect_url with a TLS-enabled socket config) with a path that does not exist or points to a regular file instead of the certificates directory.
Common situations: TLS config pointing at the CA bundle file instead of the directory; typo'd or relative path resolved from the wrong working directory; deployment container missing the mounted certs volume; rename after a certs directory reorganization.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Socket suffix cannot be empty: suffix is required for messag
- Client certificate or private key missing in {} but client a
- No valid private key found in {}
- Invalid config type for AxExecutionClientFactory. Expected A
- rate limiter decision lock poisoned
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1ec6904bf75a869f.
Report an issue: GitHub.