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
- Ensure the input is exactly 64 lowercase/uppercase hex characters (32 bytes) before calling from_hex.
- Trim whitespace and remove any '0x' prefix from the token string.
- Regenerate the session token if the value was truncated in storage or transit.
- 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
- Store tokens as hex strings and validate length at config-load time
- Trim whitespace and strip '0x' prefixes before parsing
- Use a fixed CHAR(64) column for tokens to catch truncation early
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
- Distro.lock capsule ' ' requires a canonical blake3: WASM…
- is not a 64-char hex public key
- source digest must be 64 lowercase hex characters
- a corpus produced no chunks
- a representation record must cover at least one logical…
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 preventsView on GitHub (pinned to affd8760f4)