{"record":{"id":"3b02f124d6262b9e","repo":"rustfs/rustfs","slug":"the-stored-connect-device-certificate-is-not-curre","errorCode":null,"errorMessage":"the stored Connect device certificate is not currently valid","messagePattern":"the stored Connect device certificate is not currently valid","errorType":"exception","errorClass":"HeartbeatError","httpStatus":null,"severity":"error","filePath":"rustfs/src/connect/heartbeat.rs","lineNumber":377,"sourceCode":"}\n\n#[derive(Debug, thiserror::Error)]\npub enum HeartbeatError {\n    #[error(\"Connect heartbeat endpoint must be an HTTPS base URL without credentials, query, or fragment\")]\n    Endpoint,\n    #[error(\"Connect heartbeat root CA configuration is invalid\")]\n    RootCertificate,\n    #[error(\"Connect heartbeat schedule is invalid\")]\n    Schedule,\n    #[error(\"RustFS is not registered with Connect\")]\n    NotRegistered,\n    #[error(\"the Connect device private key is missing\")]\n    IdentityMissing,\n    #[error(\"the stored Connect certificate and device private key cannot form a TLS identity\")]\n    IdentityCertificate,\n    #[error(\"the stored Connect credential name is invalid\")]\n    CredentialName,\n    #[error(\"the stored Connect device certificate is not currently valid\")]\n    CredentialExpired,\n    #[error(\"the Connect heartbeat node summary is outside protocol bounds\")]\n    NodeSummary,\n    #[error(\"the Connect heartbeat sequence is exhausted\")]\n    SequenceExhausted,\n    #[error(\"a Connect heartbeat runtime already owns this state\")]\n    AlreadyRunning,\n    #[error(\"the persisted Connect heartbeat changed while delivery was in flight\")]\n    StateConflict,\n    #[error(\"Connect heartbeat state I/O failed at {path}: {source}\")]\n    StateIo {\n        path: PathBuf,\n        #[source]\n        source: io::Error,\n    },\n    #[error(\"Connect heartbeat state at {path} is invalid: {source}\")]\n    StateInvalid {\n        path: PathBuf,","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/rustfs/rustfs/blob/201c653dcd34c2a01b9aec5991ed76176b342118/rustfs/src/connect/heartbeat.rs#L359-L395","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_credential_expired(err: &HeartbeatError) -> bool {\n    matches!(err, HeartbeatError::CredentialExpired)\n}","tryCatchPattern":"match sender.send(&pending).await {\n    Ok(delivery) => { /* handle delivery */ }\n    Err(HeartbeatError::CredentialExpired) => {\n        // Not retryable as-is: fix the clock or re-register with Connect.\n        alert(\"Connect device certificate outside its validity window\");\n        runtime.stop().await;\n    }\n    Err(e) => { tracing::warn!(error = %e, \"heartbeat failed\"); }\n}","preventionTips":["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"],"tags":["rust","rustfs","connect","heartbeat","mtls","certificate-expiry","clock-skew"],"backgroundTag":"client-certificate-expired","analyzedSha":"201c653dcd34c2a01b9aec5991ed76176b342118","analyzedAt":"2026-08-23T16:57:04.676Z","contentChangedAt":"2026-08-23T16:57:04.676Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}