{"record":{"id":"1bae583084d0ae74","repo":"rustfs/rustfs","slug":"connect-returned-an-invalid-heartbeat-response","errorCode":null,"errorMessage":"Connect returned an invalid heartbeat response","messagePattern":"Connect returned an invalid heartbeat response","errorType":"exception","errorClass":"HeartbeatError","httpStatus":null,"severity":"error","filePath":"rustfs/src/connect/heartbeat.rs","lineNumber":406,"sourceCode":"    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,\n        #[source]\n        source: serde_json::Error,\n    },\n    #[error(\"Connect heartbeat state at {path} violates the protocol invariants\")]\n    StateCorrupt { path: PathBuf },\n    #[cfg(unix)]\n    #[error(\"Connect heartbeat state at {path} has mode {mode:o}, expected {expected:o}\")]\n    StatePermissions { path: PathBuf, mode: u32, expected: u32 },\n    #[error(\"Connect heartbeat response exceeded 64 KiB\")]\n    ResponseTooLarge,\n    #[error(\"Connect returned an invalid heartbeat response\")]\n    Response,\n    #[error(transparent)]\n    Url(#[from] url::ParseError),\n    #[error(transparent)]\n    Transport(#[from] reqwest::Error),\n    #[error(transparent)]\n    Identity(#[from] IdentityError),\n    #[error(transparent)]\n    IdentityStore(#[from] StoreError),\n    #[error(transparent)]\n    CredentialStore(#[from] CredentialStoreError),\n    #[error(transparent)]\n    CredentialValidation(#[from] CredentialValidationError),\n}\n\nimpl From<TelemetryError> for HeartbeatError {\n    fn from(error: TelemetryError) -> Self {\n        match error {","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/rustfs/rustfs/blob/201c653dcd34c2a01b9aec5991ed76176b342118/rustfs/src/connect/heartbeat.rs#L388-L424","documentation":"The server returned 200 OK but the body is not a valid heartbeat response (heartbeat.rs:137-148): JSON deserialization into HeartbeatResponse failed, accepted_version != \"v1\", more than 32 capability hints, any hint longer than 32 chars, or server_time is not an exact RFC3339 UTC-seconds timestamp (is_exact_utc_seconds, telemetry.rs:195-201 -- must end in Z with zero offset and second precision).","triggerScenarios":"A proxy returning 200 with an HTML body; a Connect control plane speaking a different protocol version; a server bug emitting millisecond timestamps or non-UTC offsets.","commonSituations":"Version skew between rustfs-agent and the Connect backend; middleboxes synthesizing 200 responses; backend regressions in the response envelope.","solutions":["Capture the raw response body (debug proxy or server-side logs) to see which of the five checks failed","Confirm the Connect backend protocol version matches the agent (v1)","Remove or bypass any middlebox that rewrites response bodies"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_invalid_response(err: &HeartbeatError) -> bool {\n    matches!(err, HeartbeatError::Response)\n}","tryCatchPattern":"Err(HeartbeatError::Response) => {\n    // 200 with a bad envelope: capture the body via a debug proxy to see\n    // which check failed (version, hints, or server_time format).\n    capture_response_body(&endpoint).await;\n    alert(\"Connect returned an invalid heartbeat response\");\n}","preventionTips":["Keep agent and Connect backend protocol versions in sync","Do not put body-rewriting middleboxes on the telemetry path","Add an integration test that validates a captured response envelope"],"tags":["rust","rustfs","connect","heartbeat","response-validation","protocol"],"backgroundTag":"invalid-server-response","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"}