{"record":{"id":"d9c023f7345ad134","repo":"linera-io/linera-protocol","slug":"invalid-address-value-s","errorCode":null,"errorMessage":"Invalid address value: {s}","messagePattern":"Invalid address value: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-base/src/identifiers.rs","lineNumber":1242,"sourceCode":"                    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 {\n        Display::fmt(&self.0, f)\n    }\n}\n\nimpl std::str::FromStr for ChainId {\n    type Err = CryptoError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Ok(ChainId(CryptoHash::from_str(s)?))\n    }\n}\n\nimpl TryFrom<&[u8]> for ChainId {","sourceCodeStart":1224,"sourceCodeEnd":1260,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-base/src/identifiers.rs#L1224-L1260","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet owner: AccountOwner = s.parse()?; // 'Invalid address value: 0x1234'\n\n// after\nuse regex::Regex;\nlet re = Regex::new(r\"^0x(?:[0-9a-fA-F]{64}|[0-9a-fA-F]{40}|[0-9a-fA-F]{2})$\").unwrap();\nanyhow::ensure!(re.is_match(s.trim()), \"owner must be 0x + 64, 40 or 2 hex chars, got: {s}\");\nlet owner: AccountOwner = s.trim().parse()?;","handlingStrategy":"validation","validationCode":"fn valid_account_owner_shape(s: &str) -> bool {\n    let Some(hex) = s.strip_prefix(\"0x\") else { return false };\n    hex.len() == 64 || hex.len() == 40 || (hex.len() == 2 && hex.chars().all(|c| c.is_ascii_hexdigit()))\n}\n\n// before parsing user/config input:\nanyhow::ensure!(valid_account_owner_shape(input), \"malformed AccountOwner: {input}\");","typeGuard":"fn is_valid_account_owner_str(s: &str) -> bool {\n    AccountOwner::from_str(s).is_ok()\n}","tryCatchPattern":"match AccountOwner::from_str(&input) {\n    Ok(owner) => owner,\n    Err(err) if err.to_string().starts_with(\"Invalid address value\") => {\n        return Err(anyhow::anyhow!(\"owner must be 0x + 64/40/2 hex chars: {input}\").into());\n    }\n    Err(err) => return Err(err.into()),\n}","preventionTips":["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."],"tags":["parsing","address","account-owner","validation","rust","linera-base"],"backgroundTag":"invalid-address-format","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}