{"record":{"id":"0413e6e7d7c39ec3","repo":"linera-io/linera-protocol","slug":"invalid-label-hex-e","errorCode":null,"errorMessage":"invalid {label} hex: {e}","messagePattern":"invalid (.+?) hex: (.+?)","errorType":"validation","errorClass":"async_graphql::Error","httpStatus":null,"severity":"error","filePath":"linera-bridge/contracts/evm-bridge/src/service.rs","lineNumber":72,"sourceCode":"    }\n\n    async fn handle_query(&self, request: Request) -> Response {\n        let schema = Schema::build(\n            self.clone(),\n            MutationRoot {\n                runtime: self.runtime.clone(),\n            },\n            EmptySubscription,\n        )\n        .finish();\n        schema.execute(request).await\n    }\n}\n\n/// Decodes a hex string (optional `0x` prefix) into bytes.\nfn decode_hex(label: &str, s: &str) -> async_graphql::Result<Vec<u8>> {\n    hex::decode(s.strip_prefix(\"0x\").unwrap_or(s))\n        .map_err(|e| async_graphql::Error::new(format!(\"invalid {label} hex: {e}\")))\n}\n\n/// Decodes a hex string into a fixed-size byte array.\nfn decode_hex_array<const N: usize>(label: &str, s: &str) -> async_graphql::Result<[u8; N]> {\n    decode_hex(label, s)?.as_slice().try_into().map_err(|_| {\n        async_graphql::Error::new(format!(\n            \"{label} must be exactly {N} bytes ({} hex chars)\",\n            N * 2\n        ))\n    })\n}\n\n/// GraphQL mutation root: schedules bridge operations submitted by a client (the\n/// demo UI, an admin tool, or a custom relayer). The application bytecode — and\n/// thus this interface — cannot change after deployment, so every\n/// [`BridgeOperation`] is exposed; on-chain authorization still gates each.\n/// Byte-array arguments are hex-encoded strings (with or without `0x`).\npub struct MutationRoot {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-bridge/contracts/evm-bridge/src/service.rs#L54-L90","documentation":"decode_hex is the shared helper the EVM bridge service uses to hex-decode GraphQL arguments (with optional 0x prefix) for decode_hex_array and process_deposit. It fails whenever hex::decode rejects the input: a non-hex character, an odd number of hex digits, or stray characters such as whitespace, quotes, or underscores. The message names which label (argument) failed and echoes the hex::decode cause.","triggerScenarios":"Sending a GraphQL query/mutation to the evm-bridge service (e.g. process_deposit, or any arg decoded through decode_hex_array) where the argument contains characters outside [0-9a-fA-F] (after an optional 0x prefix), has odd length, or includes whitespace/newlines/quotes from shell or JSON copy-paste.","commonSituations":"Pasting an ENS name, decimal amount, or base58 value where a hex hash is expected; a truncated or double-prefixed hash (\"0x0x…\"); values copied from logs that include quotes or trailing whitespace; sending the same string to both keccak-decoded and hex-decoded fields and only one being valid hex.","solutions":["Send only even-length hex digits [0-9a-f] (case-insensitive) with at most one leading 0x prefix; re-copy the value from its source (transaction receipt, event log).","Strip whitespace/newlines and any duplicate 0x prefix before sending; check for shell quoting issues (\"$…\" expansion, smart quotes).","If the value is a decimal or other encoding, convert it to hex first (e.g. `cast --to-hex`, `toHex`), keeping the required byte length in mind."],"exampleFix":"// before\nprocess_deposit(depositId: \"0x12g4\")  // 'g' is not a hex digit -> invalid depositId hex\n\n// after\nprocess_deposit(depositId: \"0x12f4\")  // even-length [0-9a-f] digits only","handlingStrategy":"validation","validationCode":"fn is_valid_hex_arg(s: &str) -> bool {\n    let body = s.strip_prefix(\"0x\").unwrap_or(s);\n    !body.is_empty() && body.len() % 2 == 0 && body.bytes().all(|b| b.is_ascii_hexdigit())\n}","typeGuard":"fn is_valid_hex(s: &str) -> bool {\n    let body = s.strip_prefix(\"0x\").unwrap_or(s).trim();\n    !body.is_empty() && body.len() % 2 == 0 && body.bytes().all(|b| b.is_ascii_hexdigit())\n}","tryCatchPattern":null,"preventionTips":["Validate hex args client-side (regex ^0x[0-9a-fA-F]*$ plus even length) before sending the GraphQL request.","Copy hashes straight from the transaction receipt/event log rather than retyping them.","Normalize once at the edge: strip whitespace and duplicate 0x prefixes in a single helper used by all callers."],"tags":["rust","graphql","hex","evm-bridge","input-validation"],"backgroundTag":"invalid-hex-string","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}