linera-io/linera-protocol · error
Invalid address value: {s}
Error message
Invalid address value: {s} What it means
AccountOwner::from_str failed to parse the input as any of the three supported owner-address forms. A valid AccountOwner string is '0x' followed by either 64 hex chars (32-byte Address32, a CryptoHash), 40 hex chars (20-byte Address20, an EVM-style address), or exactly 2 hex chars (a Reserved value 0x00-0xFF). Anything else — wrong prefix, odd length, non-hex characters, or a 0x-prefixed string of an unsupported length — reaches the final bail.
Source
Thrown at linera-base/src/identifiers.rs:1242
return Ok(AccountOwner::Address32(hash));
}
} else if s.len() == 40 {
let address = hex::decode(s)?;
if address.len() != 20 {
anyhow::bail!("Invalid address length: {s}");
}
let address = <[u8; 20]>::try_from(address.as_slice()).unwrap();
return Ok(AccountOwner::Address20(address));
}
if s.len() == 2 {
let bytes = hex::decode(s)?;
if bytes.len() == 1 {
let value = u8::from_be_bytes(bytes.try_into().expect("one byte"));
return Ok(AccountOwner::Reserved(value));
}
}
}
anyhow::bail!("Invalid address value: {s}");
}
}
impl fmt::Display for ChainId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl std::str::FromStr for ChainId {
type Err = CryptoError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(ChainId(CryptoHash::from_str(s)?))
}
}
impl TryFrom<&[u8]> for ChainId {View on GitHub (pinned to 6c226ddcb3)
Solutions
- Check the string against the three accepted shapes: ^0x[0-9a-fA-F]{64}$ (Address32), ^0x[0-9a-fA-F]{40}$ (Address20), ^0x[0-9a-fA-F]{2}$ (Reserved); fix length/prefix accordingly.
- If you meant an EVM address, ensure it is the full 20-byte hex (40 chars) with the 0x prefix.
- If you meant a reserved/system owner, use exactly two hex digits like '0x01'.
- If the value comes from user input or a config file, validate with a regex before parsing and surface a field-specific error.
Example fix
// before
let owner: AccountOwner = s.parse()?; // 'Invalid address value: 0x1234'
// after
use regex::Regex;
let re = Regex::new(r"^0x(?:[0-9a-fA-F]{64}|[0-9a-fA-F]{40}|[0-9a-fA-F]{2})$").unwrap();
anyhow::ensure!(re.is_match(s.trim()), "owner must be 0x + 64, 40 or 2 hex chars, got: {s}");
let owner: AccountOwner = s.trim().parse()?; Defensive patterns
Strategy: validation
Validate before calling
fn valid_account_owner_shape(s: &str) -> bool {
let Some(hex) = s.strip_prefix("0x") else { return false };
hex.len() == 64 || hex.len() == 40 || (hex.len() == 2 && hex.chars().all(|c| c.is_ascii_hexdigit()))
}
// before parsing user/config input:
anyhow::ensure!(valid_account_owner_shape(input), "malformed AccountOwner: {input}"); Type guard
fn is_valid_account_owner_str(s: &str) -> bool {
AccountOwner::from_str(s).is_ok()
} Try / catch
match AccountOwner::from_str(&input) {
Ok(owner) => owner,
Err(err) if err.to_string().starts_with("Invalid address value") => {
return Err(anyhow::anyhow!("owner must be 0x + 64/40/2 hex chars: {input}").into());
}
Err(err) => return Err(err.into()),
} Prevention
- Validate the 0x-prefix and hex length (64/40/2) at the config/CLI boundary before calling parse.
- Normalize input once (trim whitespace, lowercase hex) at ingestion.
- Write round-trip tests: format!("{owner}").parse() == Ok(owner) for all three variants.
When it happens
Trigger: Calling 'AccountOwner::from_str(s)', or deserializing an AccountOwner from a human-readable format (JSON config, CLI argument, GraphQL input), with e.g. '0x1234' (4 hex chars), 'e1e2...'/missing 0x prefix, a 64-char string that is not a valid CryptoHash, an all-lowercase/uppercase issue is fine but a non-hex char like '0xzz' is not, or an EVM checksummed address is fine hex-wise but any typo in length throws.
Common situations: Passing an EVM address with the '0x' prefix removed or truncated; copy-pasting a ChainId (64 hex chars after 0x, which is valid Address32) into a field that was then edited; config files migrated between versions that used different address encodings; mixing up Owner (AccountOwner) and Account (chain+owner pair) string forms.
Related errors
- Invalid address length: {s}
- Invalid blob ID: {s}
- Invalid parsing of GenericApplicationId
- Invalid stream ID: {s}
- owner should be different from spender
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/d9c023f7345ad134.
Report an issue: GitHub.