{"record":{"id":"d9e799540035147d","repo":"clockworklabs/SpacetimeDB","slug":"unable-to-parse-invalid-saved-server-fingerprint-a","errorCode":null,"errorMessage":"Unable to parse invalid saved server fingerprint as ECDSA public key.\nUpdate the server's fingerprint with:\n\tspacetime server fingerprint {}","messagePattern":"Unable to parse invalid saved server fingerprint as ECDSA public key\\.\nUpdate the server's fingerprint with:\n\tspacetime server fingerprint (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/config.rs","lineNumber":759,"sourceCode":"        // (see https://github.com/clockworklabs/SpacetimeDB/pull/1341#issuecomment-2150857432).\n        if let Err(e) = atomic_write(&home_path.0, config) {\n            eprintln!(\"Could not save config file: {e}\")\n        }\n    }\n\n    pub fn server_decoding_key(&self, server: Option<&str>) -> anyhow::Result<DecodingKey> {\n        self.server_fingerprint(server).and_then(|fing| {\n            if let Some(fing) = fing {\n                DecodingKey::from_ec_pem(fing.as_bytes()).with_context(|| {\n                    format!(\n                        \"Unable to parse invalid saved server fingerprint as ECDSA public key.\nUpdate the server's fingerprint with:\n\\tspacetime server fingerprint {}\",\n                        server.unwrap_or(\"\")\n                    )\n                })\n            } else {\n                Err(anyhow::anyhow!(\n                    \"No fingerprint saved for server: {}\",\n                    self.server_nick_or_host(server)?,\n                ))\n            }\n        })\n    }\n\n    pub fn server_nick_or_host<'a>(&'a self, server: Option<&'a str>) -> anyhow::Result<&'a str> {\n        if let Some(server) = server {\n            let (host, _) = host_or_url_to_host_and_protocol(server);\n            Ok(host)\n        } else {\n            self.home.default_server().map(ServerConfig::nick_or_host)\n        }\n    }\n\n    pub fn server_fingerprint(&self, server: Option<&str>) -> anyhow::Result<Option<&str>> {\n        if let Some(server) = server {","sourceCodeStart":741,"sourceCodeEnd":777,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/cli/src/config.rs#L741-L777","documentation":"The CLI's server_decoding_key (crates/cli/src/config.rs:759) loads the server fingerprint previously saved for that server and parses it with jsonwebtoken's DecodingKey::from_ec_pem, which requires a PEM-encoded ECDSA public key. If the saved string is corrupt, truncated, or in another format (raw hex, base64 body without PEM armor), parsing fails and the error tells you how to refresh it with `spacetime server fingerprint <server>` (the server name, or empty for the default, is interpolated).","triggerScenarios":"Running any CLI command that verifies server JWTs (login/token flows) against a server whose saved fingerprint entry in the CLI config is not valid EC PEM; hand-editing the config and breaking the PEM block; a partial write or an older tool version that stored a different fingerprint format.","commonSituations":"Config files synced/templated across machines mangling the multiline PEM; downgrading/upgrading CLI versions with changed fingerprint storage; pasting a fingerprint from docs as raw hex instead of fetching it.","solutions":["Re-record the fingerprint from the live server: `spacetime server fingerprint <host-or-nickname>` (or without an argument for the default server).","If re-fetching is not possible, remove the server's fingerprint entry from the CLI config so the next connection re-establishes it.","Check the stored value starts with `-----BEGIN PUBLIC KEY-----` and ends with the matching footer on its own line - multi-line PEM must survive whatever transport stored it."],"exampleFix":"# before: saved fingerprint is corrupt / non-PEM\nspacetime login   # Unable to parse invalid saved server fingerprint as ECDSA public key...\n# after: refresh from the server\nspacetime server fingerprint mainnet\nspacetime login","handlingStrategy":"fallback","validationCode":"// Preflight: sanity-check the stored PEM before use.\nlet fp = config.server_fingerprint(server).ok().flatten().unwrap_or_default();\nif !fp.is_empty() && !(fp.trim_start().starts_with(\"-----BEGIN\") && fp.contains(\"-----END\")) {\n    anyhow::bail!(\"saved fingerprint is not PEM; run: spacetime server fingerprint {}\", server.unwrap_or(\"\"));\n}","typeGuard":null,"tryCatchPattern":"# On failure, refresh the fingerprint and retry once:\nspacetime login || { spacetime server fingerprint \"$SERVER\" && spacetime login; }","preventionTips":["Refresh fingerprints with `spacetime server fingerprint <server>` right after server key rotations.","Never hand-edit or single-line the PEM block in the CLI config; keep it byte-exact multiline.","When templating configs across machines, base64 the whole config file rather than inlining the PEM into other formats."],"tags":["spacetimedb","cli","config","fingerprint","pem","ecdsa"],"backgroundTag":"invalid-server-fingerprint","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}