astrid-runtime/astrid · error · io::Error

InvalidData

InvalidData

Error message

session token hex must be 64 chars, got {}

What it means

SessionToken::from_hex parses a hex-encoded 32-byte session token and requires the input string to be exactly 64 hex characters. A string of any other length is rejected up front with InvalidData before any decoding is attempted. This guarantees the token always decodes to exactly [u8; 32].

Solutions

  1. Ensure the input is exactly 64 lowercase/uppercase hex characters (32 bytes) before calling from_hex.
  2. Trim whitespace and remove any '0x' prefix from the token string.
  3. Regenerate the session token if the value was truncated in storage or transit.
  4. If you have raw bytes, construct the token directly rather than round-tripping through a lossy string.

Example fix

// before
let token = SessionToken::from_hex(&config.session_token)?; // "a3f1..." (60 chars)
// after
let hex = config.session_token.trim();
assert!(hex.len() == 64, "token must be 64 hex chars");
let token = SessionToken::from_hex(hex)?;
Defensive patterns

Strategy: validation

Validate before calling

fn valid_token_hex(s: &str) -> bool {
    s.len() == 64 && s.bytes().all(|b| b.is_ascii_hexdigit())
}

Prevention

When it happens

Trigger: Calling SessionToken::from_hex with a string whose byte length is not 64 — e.g. a truncated token, a token with extra whitespace, a base64-encoded token, or a raw 32-byte value pasted as text.

Common situations: Copy/paste truncating or padding the token; storing tokens in a fixed-width DB column that truncated them; accidentally encoding the token as base64 instead of hex; including a '0x' prefix which adds 2 characters.

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/7d4281a97f83d3d3. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-core/src/session_token.rs:83

    #[must_use]
    pub fn to_hex(&self) -> String {
        let mut hex = String::with_capacity(64);
        for byte in &self.0 {
            use fmt::Write;
            let _ = write!(hex, "{byte:02x}");
        }
        hex
    }

    /// Decode a hex-encoded token string.
    ///
    /// # Errors
    ///
    /// Returns an error if the hex string is not exactly 64 characters or
    /// contains invalid hex digits.
    pub fn from_hex(hex: &str) -> Result<Self, io::Error> {
        if hex.len() != 64 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("session token hex must be 64 chars, got {}", hex.len()),
            ));
        }
        let mut bytes = [0u8; 32];
        for (i, chunk) in hex.as_bytes().chunks(2).enumerate() {
            let hi = hex_digit(chunk[0])?;
            let lo = hex_digit(chunk[1])?;
            bytes[i] = (hi << 4) | lo;
        }
        Ok(Self(bytes))
    }

    /// Write the token to a file with owner-only permissions (0o600).
    ///
    /// On Unix, this uses write-then-rename atomicity: writes to a temporary
    /// file at 0o600 (via `OpenOptions::mode` to avoid a TOCTOU permissions
    /// window), then atomically renames it to the target path. This prevents

View on GitHub (pinned to affd8760f4)