astrid-runtime/astrid · error

is not a 64-char hex public key

Error message

{} is not a 64-char hex public key

What it means

`read_public` loads a keypair's public-key file and requires its trimmed contents to be exactly 64 ASCII hex characters (a 32-byte ed25519 public key). Any other content — empty, truncated, base64, or with stray characters — bails with the path named in the message.

Solutions

  1. Inspect the file named in the error and restore the correct 64-char hex public key.
  2. Re-derive it if possible (e.g. from the private key) or regenerate the keypair with `astrid keypair generate <name> --force`.
  3. Re-run with --public-key <hex> inline instead of --keypair if you have the key elsewhere.
  4. Ensure whatever writes the file emits lowercase/uppercase hex only, no prefixes.

Example fix

// before (file content)
MCowBQYDK2VwAyEA...   # base64
// after
0f1e2d3c4b5a69788796a5b4c3d2e1f00f1e2d3c4b5a69788796a5b4c3d2e1f0
Defensive patterns

Strategy: validation

Validate before calling

HEX=$(tr -d '[:space:]' < "$KEYDIR/$NAME.pub.hex"); [[ $HEX =~ ^[0-9a-fA-F]{64}$ ]] || echo "corrupt public key for $NAME" >&2

Prevention

When it happens

Trigger: The .pub.hex file is empty, truncated, contains base64 instead of hex, has extra whitespace/newlines beyond trim, or was overwritten by another tool; also hit whenever load_public_key_hex resolves --keypair for invite redeem.

Common situations: Interrupted write during keypair generation; manual copy-paste of the key introduced formatting; editor or sync tool mangled the file; version/tooling that wrote a different encoding.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/1cec412c7e285e69. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-cli/src/commands/keypair.rs:464

    let text = toml::to_string_pretty(meta).context("serialise keypair meta")?;
    let tmp = path.with_extension(format!("{}.tmp", std::process::id()));
    fs::write(&tmp, text.as_bytes())?;
    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        fs::set_permissions(&tmp, fs::Permissions::from_mode(0o600))?;
    }
    fs::rename(&tmp, path).inspect_err(|_| {
        let _ = fs::remove_file(&tmp);
    })?;
    Ok(())
}

fn read_public(path: &Path) -> Result<String> {
    let raw = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?;
    let trimmed = raw.trim().to_string();
    if trimmed.len() != 64 || !trimmed.chars().all(|c| c.is_ascii_hexdigit()) {
        bail!("{} is not a 64-char hex public key", path.display());
    }
    Ok(trimmed)
}

fn read_meta(paths: &KeyPaths) -> Result<KeyMeta> {
    let text = fs::read_to_string(&paths.meta)
        .with_context(|| format!("read {}", paths.meta.display()))?;
    let meta: KeyMeta =
        toml::from_str(&text).with_context(|| format!("parse {}", paths.meta.display()))?;
    if meta.schema_version > META_SCHEMA_VERSION {
        bail!(
            "keypair {} was written by a newer astrid (schema {} > {})",
            paths.meta.display(),
            meta.schema_version,
            META_SCHEMA_VERSION
        );
    }
    if meta.schema_version < META_SCHEMA_VERSION {

View on GitHub (pinned to affd8760f4)