clockworklabs/SpacetimeDB · error

No fingerprint saved for server: {}

Error message

No fingerprint saved for server: {}

What it means

server_decoding_key builds a JWT DecodingKey from the server's pinned ECDSA public key. Here server_fingerprint resolved the server's config entry, but its ecdsa_public_key field is None, so there is nothing to build a key from and token verification cannot proceed. Fingerprints are saved when the CLI pins a server's identity; an entry created by `server add` starts without one. The sibling error in the same function handles the 'fingerprint exists but is invalid PEM' case and suggests `spacetime server fingerprint <server>`.

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 524b4487d9)

Solutions

  1. Fetch and store the fingerprint explicitly: `spacetime server fingerprint <server>`
  2. Re-login against the server (`spacetime login --server <server>`) so the CLI connects and persists the server's public key
  3. Inspect `spacetime server list` / the config file to confirm which entries lack a fingerprint before scripting dependent commands

Example fix

# before
spacetime publish --server myserver mydb   # error: No fingerprint saved for server: myserver

# after
spacetime server fingerprint myserver
spacetime publish --server myserver mydb
Defensive patterns

Strategy: try-catch

Validate before calling

# Ensure a fingerprint is pinned before running token-verified commands
spacetime server fingerprint "$SERVER" || spacetime login --server "$SERVER"

Try / catch

match config.server_decoding_key(Some(server)) {
    Ok(key) => key,
    Err(e) if e.to_string().starts_with("No fingerprint saved for server") => {
        // remediate: fetch and store the server's public key, then retry once
        run!("spacetime", ["server", "fingerprint", server])?;
        config.server_decoding_key(Some(server))?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Any operation that verifies server tokens (login/logout flows, authenticated requests that check the server's identity) against a server whose config entry exists but never had a fingerprint stored — e.g. added via `spacetime server add` and never connected to, or the fingerprint was cleared.

Common situations: Freshly added server before first successful connection; config edited by hand and the key field dropped; CI environment provisioned by copying a config that was saved before the first login; server re-provisioned with a new key and the stale entry recreated empty.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/5c76fae700929275. Report an issue: GitHub.