rustfs/rustfs · error · HeartbeatError
the stored Connect device certificate is not currently valid
Error message
the stored Connect device certificate is not currently valid
What it means
The stored Connect device certificate's validity window does not cover the current time. Before every heartbeat POST, TelemetryTransport::authenticated_client checks `now < credential.not_before_unix || now >= credential.not_after_unix` (rustfs/src/connect/telemetry.rs:131-134) and this variant (converted from TelemetryError::CredentialExpired at heartbeat.rs:432) is returned when the check fails. The runtime refuses to send telemetry with a credential the control plane would reject anyway.
Source
Thrown at rustfs/src/connect/heartbeat.rs:377
}
#[derive(Debug, thiserror::Error)]
pub enum HeartbeatError {
#[error("Connect heartbeat endpoint must be an HTTPS base URL without credentials, query, or fragment")]
Endpoint,
#[error("Connect heartbeat root CA configuration is invalid")]
RootCertificate,
#[error("Connect heartbeat schedule is invalid")]
Schedule,
#[error("RustFS is not registered with Connect")]
NotRegistered,
#[error("the Connect device private key is missing")]
IdentityMissing,
#[error("the stored Connect certificate and device private key cannot form a TLS identity")]
IdentityCertificate,
#[error("the stored Connect credential name is invalid")]
CredentialName,
#[error("the stored Connect device certificate is not currently valid")]
CredentialExpired,
#[error("the Connect heartbeat node summary is outside protocol bounds")]
NodeSummary,
#[error("the Connect heartbeat sequence is exhausted")]
SequenceExhausted,
#[error("a Connect heartbeat runtime already owns this state")]
AlreadyRunning,
#[error("the persisted Connect heartbeat changed while delivery was in flight")]
StateConflict,
#[error("Connect heartbeat state I/O failed at {path}: {source}")]
StateIo {
path: PathBuf,
#[source]
source: io::Error,
},
#[error("Connect heartbeat state at {path} is invalid: {source}")]
StateInvalid {
path: PathBuf,View on GitHub (pinned to 201c653dcd)
Solutions
- Check and correct the system clock (NTP/chrony/systemd-timesyncd), then restart -- clock skew is the most common cause
- If the clock is correct, the certificate is genuinely outside its window: re-register this RustFS deployment with Connect using a fresh registration token to obtain a new device credential
- Inspect the stored credential's notBefore/notAfter timestamps to confirm which side of the window `now` falls on
Defensive patterns
Strategy: try-catch
Type guard
fn is_credential_expired(err: &HeartbeatError) -> bool {
matches!(err, HeartbeatError::CredentialExpired)
} Try / catch
match sender.send(&pending).await {
Ok(delivery) => { /* handle delivery */ }
Err(HeartbeatError::CredentialExpired) => {
// Not retryable as-is: fix the clock or re-register with Connect.
alert("Connect device certificate outside its validity window");
runtime.stop().await;
}
Err(e) => { tracing::warn!(error = %e, "heartbeat failed"); }
} Prevention
- Run NTP/chrony and alert on drift beyond 60 seconds
- Monitor the credential's notAfter and re-register before it passes
- Never restore an old credential store from backup without checking its validity window
When it happens
Trigger: Calling heartbeat send paths when the system clock is earlier than the certificate's notBefore, at/past its notAfter, or skewed far enough to fall outside the window; restoring an old credential store; a certificate issued against a since-corrected clock.
Common situations: NTP drift or a stopped clock in VMs/containers; a VM resumed from snapshot with stale time; the device certificate simply aged past expiry because re-registration never happened.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- state path has no parent
- state filename is invalid
- Connect heartbeat schedule is invalid
- RustFS is not registered with Connect
- the Connect device private key is missing
AI-assisted analysis of rustfs/rustfs@201c653dcd (2026-08-23).
Data as JSON: /api/errors/3b02f124d6262b9e.
Report an issue: GitHub.