{"record":{"id":"03369bd7f455de8b","repo":"linera-io/linera-protocol","slug":"invalid-address-length-s","errorCode":null,"errorMessage":"Invalid address length: {s}","messagePattern":"Invalid address length: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-base/src/identifiers.rs","lineNumber":1229,"sourceCode":"        };\n\n        Ok(())\n    }\n}\n\nimpl std::str::FromStr for AccountOwner {\n    type Err = anyhow::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        if let Some(s) = s.strip_prefix(\"0x\") {\n            if s.len() == 64 {\n                if let Ok(hash) = CryptoHash::from_str(s) {\n                    return Ok(AccountOwner::Address32(hash));\n                }\n            } else if s.len() == 40 {\n                let address = hex::decode(s)?;\n                if address.len() != 20 {\n                    anyhow::bail!(\"Invalid address length: {s}\");\n                }\n                let address = <[u8; 20]>::try_from(address.as_slice()).unwrap();\n                return Ok(AccountOwner::Address20(address));\n            }\n            if s.len() == 2 {\n                let bytes = hex::decode(s)?;\n                if bytes.len() == 1 {\n                    let value = u8::from_be_bytes(bytes.try_into().expect(\"one byte\"));\n                    return Ok(AccountOwner::Reserved(value));\n                }\n            }\n        }\n        anyhow::bail!(\"Invalid address value: {s}\");\n    }\n}\n\nimpl fmt::Display for ChainId {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {","sourceCodeStart":1211,"sourceCodeEnd":1247,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-base/src/identifiers.rs#L1211-L1247","documentation":"AccountOwner::from_str parses 0x-prefixed hex strings into one of three shapes: 64 hex chars → Address32 (a CryptoHash), 40 hex chars → Address20 (an EVM-style address), 2 hex chars → Reserved(u8). The 'Invalid address length' bail guards the 40-char branch when the decoded bytes are not exactly 20; since 40 hex characters always decode to 20 bytes, this arm is effectively a defensive unreachable check — malformed input more commonly surfaces as the adjacent 'Invalid address value' error or a hex decode error. Note this is a returned Err (anyhow::bail!), not a panic.","triggerScenarios":"Parsing an owner string whose hex length doesn't match the 64/40/2 forms (falls through to 'Invalid address value'), contains non-hex characters (hex decode error), or — for this specific message — any hypothetical path where a 40-char string decodes to a length other than 20 bytes. Callers hit it via AccountOwner::from_str in CLI parsing, GraphQL input, or config deserialization.","commonSituations":"Copying Ethereum addresses with checksummed mixed-case (hex::decode accepts mixed case, so usually fine) or with missing/extra digits; passing a 20-byte address where a 32-byte owner (CryptoHash) is expected or vice versa; forgetting the 0x prefix; feeding a contract address where an AccountOwner string is wanted.","solutions":["Use exactly 40 hex characters (20 bytes) with the 0x prefix for EVM-style Address20 owners","Use 64 hex characters for 32-byte Address32 owners and 2 hex characters for Reserved values","Validate owner strings in tests with AccountOwner::from_str before shipping configs or scripts"],"exampleFix":"// before\nlet owner: AccountOwner = \"0x8da6bac7dc85b63b4326c28926a1c168786e3fc912\".parse()?; // 41 hex chars\n\n// after\nlet owner: AccountOwner = \"0x8da6bac7dc85b63b4326c28926a1c168786e3fc9\".parse()?; // 40 hex chars","handlingStrategy":"validation","validationCode":"fn is_valid_account_owner(s: &str) -> bool {\n    let Some(hex) = s.strip_prefix(\"0x\") else { return false };\n    match hex.len() {\n        64 => hex.chars().all(|c| c.is_ascii_hexdigit()), // Address32\n        40 => hex.chars().all(|c| c.is_ascii_hexdigit()), // Address20\n        2 => hex.chars().all(|c| c.is_ascii_hexdigit()),  // Reserved(u8)\n        _ => false,\n    }\n}\nassert!(is_valid_account_owner(input), \"not a valid AccountOwner: {input}\");","typeGuard":"fn parse_account_owner(s: &str) -> Option<linera_base::identifiers::AccountOwner> {\n    s.parse().ok()\n}","tryCatchPattern":"match \"0x8da...\".parse::<AccountOwner>() {\n    Ok(owner) => use_owner(owner),\n    Err(e) => eprintln!(\"invalid AccountOwner (need 0x + 64/40/2 hex chars): {e:#}\"),\n}","preventionTips":["Always prefix owner addresses with 0x and use exactly 40 hex chars for EVM-style owners","Parse owner strings at the system boundary (CLI/config/GraphQL) and reject early","Round-trip test: owner.to_string().parse::<AccountOwner>().unwrap() for values you emit"],"tags":["identifiers","address","parsing","account-owner","hex"],"backgroundTag":"invalid-address-format","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}