astrid-runtime/astrid · error
tls.cert-path and tls.key-path resolve to the same file
Error message
tls.cert-path and tls.key-path resolve to the same file ({}); separate them What it means
Defensive check in GatewayConfig::validate: tls.cert-path and tls.key-path resolve to the same file — the classic copy-paste typo of pointing both at the certificate — which would make TLS unusable at handshake time.
Solutions
- Point tls.key-path at the private-key PEM and tls.cert-path at the certificate PEM — two different files
- If only one file exists, regenerate or export the missing half of the keypair
- Re-check the config after templating/secret injection that may have collapsed both values
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at crates/astrid-gateway/src/config.rs:169 when the library encounters an invalid state.
Common situations: See trigger scenarios.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/ca7f29cb9a170a64.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-gateway/src/config.rs:169
// clear error.
if !tls.cert_path.is_file() {
anyhow::bail!(
"tls.cert-path {} is not a regular file — refusing to boot the gateway",
tls.cert_path.display()
);
}
if !tls.key_path.is_file() {
anyhow::bail!(
"tls.key-path {} is not a regular file — refusing to boot the gateway",
tls.key_path.display()
);
}
// Defensive: catch the copy-paste typo where cert+key
// point at the same file. The rustls PEM parser will
// happily try to load a private key out of the cert chain
// and produce a cryptic error; surface the problem here.
if tls.cert_path == tls.key_path {
anyhow::bail!(
"tls.cert-path and tls.key-path resolve to the same file ({}); separate them",
tls.cert_path.display()
);
}
crate::tls::warn_if_key_is_too_open(&tls.key_path);
}
Ok(())
}
}
/// Validate a single CORS origin string. Origins MUST be of the form
/// `scheme://host[:port]` with no path, query, or fragment — that's
/// what the browser sends in `Origin:` and what the response's
/// `Access-Control-Allow-Origin:` is byte-matched against. A
/// `https://app.example/` (trailing slash) would silently fail to
/// match a real preflight; rejecting it here is what makes that
/// surfacable.
fn validate_cors_origin(raw: &str) -> anyhow::Result<()> {View on GitHub (pinned to affd8760f4)