{"record":{"id":"88841a34340cd1ed","repo":"rustfs/rustfs","slug":"failed-to-read-the-connect-registration-token","errorCode":null,"errorMessage":"failed to read the Connect registration token","messagePattern":"failed to read the Connect registration token","errorType":"exception","errorClass":"TokenError","httpStatus":null,"severity":"error","filePath":"rustfs/src/connect/registration.rs","lineNumber":122,"sourceCode":"\n        Ok(Self {\n            registration_token_uid: document.registration_token_uid,\n            registration_token_secret: Zeroizing::new(document.registration_token_secret),\n            organization_uid: document.organization_uid,\n            cluster_uid: document.cluster_uid,\n            challenge_nonce: document.challenge_nonce,\n            expires_unix: document.expires_unix,\n        })\n    }\n\n    pub(crate) fn secret(&self) -> &str {\n        &self.registration_token_secret\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum TokenError {\n    #[error(\"failed to read the Connect registration token\")]\n    Read(#[source] std::io::Error),\n    #[error(\"Connect registration token configuration is invalid\")]\n    Invalid(#[source] serde_json::Error),\n    #[error(\"Connect registration token secret must be 32-byte unpadded base64url\")]\n    SecretShape,\n    #[error(\"Connect registration token configuration exceeds 16 KiB\")]\n    TooLarge,\n    #[error(\"Connect registration token fields do not match the protocol schema\")]\n    Shape,\n}\n\n#[derive(Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub(crate) struct RegistrationRequest<'a> {\n    protocol_version: &'static str,\n    request_id: &'a str,\n    registration_token_uid: &'a str,\n    registration_token_secret: &'a str,","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/rustfs/rustfs/blob/201c653dcd34c2a01b9aec5991ed76176b342118/rustfs/src/connect/registration.rs#L104-L140","documentation":"Loading a Connect registration token with RegistrationToken::from_reader failed at the I/O layer before any parsing: the std::io::Error raised while reading up to 16 KiB+1 bytes is wrapped unchanged as this variant's source (registration.rs:77-80). Inspect the wrapped error for the real cause - NotFound, PermissionDenied, UnexpectedEof, and so on.","triggerScenarios":"RegistrationToken::from_reader(reader) where opening or reading fails: missing token file, permission denied, a directory in the file's place, or a stream that errors mid-read (broken pipe, early close).","commonSituations":"Wrong path in config (relative versus absolute, typo); token not yet provisioned or already rotated away; service user lacking read permission; reading from a pipe whose writer closed early.","solutions":["Match on TokenError::Read and log the wrapped io::Error - it carries the real OS-level cause.","Verify the path exists and the service user can read it (stat the file as that user).","Re-provision or re-download the token if it was rotated out or never written.","For pipe-based readers, keep the writer open until EOF."],"exampleFix":"// before\nlet token = RegistrationToken::from_reader(File::open(&path)?)?;\n\n// after\nlet token = match RegistrationToken::from_reader(File::open(&path)?) {\n    Ok(token) => token,\n    Err(TokenError::Read(source)) => {\n        return Err(format!(\"cannot read registration token at {}: {source}\", path.display()).into());\n    }\n    Err(other) => return Err(other.into()),\n};","handlingStrategy":"try-catch","validationCode":"let meta = std::fs::metadata(&path)?; // surfaces NotFound/PermissionDenied with clear context\nassert!(meta.is_file(), \"registration token path must be a regular file\");","typeGuard":null,"tryCatchPattern":"match RegistrationToken::from_reader(reader) {\n    Err(TokenError::Read(source)) => { /* classify via source.kind(); retry only after fixing path or permissions */ }\n    Err(TokenError::Invalid(source)) => { /* log the serde error's field and offset */ }\n    result => result,\n}","preventionTips":["Check existence and permissions of the token file at startup, before enrollment depends on it.","Fail fast with the path in the message so operators see which file failed.","Never silence the wrapped io::Error - it is the only clue separating a missing file from a permissions problem."],"tags":["rust","rustfs","connect","registration-token","io","file"],"backgroundTag":"file-read-failure","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"}