clockworklabs/SpacetimeDB · error

Unable to parse invalid saved server fingerprint as ECDSA pu

Error message

Unable to parse invalid saved server fingerprint as ECDSA public key.
Update the server's fingerprint with:
	spacetime server fingerprint {}

What it means

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).

Source

Thrown at crates/cli/src/config.rs:759

        // (see https://github.com/clockworklabs/SpacetimeDB/pull/1341#issuecomment-2150857432).
        if let Err(e) = atomic_write(&home_path.0, config) {
            eprintln!("Could not save config file: {e}")
        }
    }

    pub fn server_decoding_key(&self, server: Option<&str>) -> anyhow::Result<DecodingKey> {
        self.server_fingerprint(server).and_then(|fing| {
            if let Some(fing) = fing {
                DecodingKey::from_ec_pem(fing.as_bytes()).with_context(|| {
                    format!(
                        "Unable to parse invalid saved server fingerprint as ECDSA public key.
Update the server's fingerprint with:
\tspacetime server fingerprint {}",
                        server.unwrap_or("")
                    )
                })
            } else {
                Err(anyhow::anyhow!(
                    "No fingerprint saved for server: {}",
                    self.server_nick_or_host(server)?,
                ))
            }
        })
    }

    pub fn server_nick_or_host<'a>(&'a self, server: Option<&'a str>) -> anyhow::Result<&'a str> {
        if let Some(server) = server {
            let (host, _) = host_or_url_to_host_and_protocol(server);
            Ok(host)
        } else {
            self.home.default_server().map(ServerConfig::nick_or_host)
        }
    }

    pub fn server_fingerprint(&self, server: Option<&str>) -> anyhow::Result<Option<&str>> {
        if let Some(server) = server {

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Re-record the fingerprint from the live server: `spacetime server fingerprint <host-or-nickname>` (or without an argument for the default server).
  2. If re-fetching is not possible, remove the server's fingerprint entry from the CLI config so the next connection re-establishes it.
  3. 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.

Example fix

# before: saved fingerprint is corrupt / non-PEM
spacetime login   # Unable to parse invalid saved server fingerprint as ECDSA public key...
# after: refresh from the server
spacetime server fingerprint mainnet
spacetime login
Defensive patterns

Strategy: fallback

Validate before calling

// Preflight: sanity-check the stored PEM before use.
let fp = config.server_fingerprint(server).ok().flatten().unwrap_or_default();
if !fp.is_empty() && !(fp.trim_start().starts_with("-----BEGIN") && fp.contains("-----END")) {
    anyhow::bail!("saved fingerprint is not PEM; run: spacetime server fingerprint {}", server.unwrap_or(""));
}

Try / catch

# On failure, refresh the fingerprint and retry once:
spacetime login || { spacetime server fingerprint "$SERVER" && spacetime login; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/d9e799540035147d. Report an issue: GitHub.