linera-io/linera-protocol · error · async_graphql::Error
{label} must be exactly {N} bytes ({} hex chars)
Error message
{label} must be exactly {N} bytes ({} hex chars) What it means
After decode_hex succeeds, decode_hex_array converts the decoded bytes into a fixed-size [u8; N] for typed fields (32-byte tx hashes or topics, 20-byte addresses, etc.). try_into fails when the decoded length differs from N, so this error means the hex was valid but the wrong length. The message states the exact requirement: N bytes, i.e. N*2 hex characters.
Source
Thrown at linera-bridge/contracts/evm-bridge/src/service.rs:78
runtime: self.runtime.clone(),
},
EmptySubscription,
)
.finish();
schema.execute(request).await
}
}
/// Decodes a hex string (optional `0x` prefix) into bytes.
fn decode_hex(label: &str, s: &str) -> async_graphql::Result<Vec<u8>> {
hex::decode(s.strip_prefix("0x").unwrap_or(s))
.map_err(|e| async_graphql::Error::new(format!("invalid {label} hex: {e}")))
}
/// Decodes a hex string into a fixed-size byte array.
fn decode_hex_array<const N: usize>(label: &str, s: &str) -> async_graphql::Result<[u8; N]> {
decode_hex(label, s)?.as_slice().try_into().map_err(|_| {
async_graphql::Error::new(format!(
"{label} must be exactly {N} bytes ({} hex chars)",
N * 2
))
})
}
/// GraphQL mutation root: schedules bridge operations submitted by a client (the
/// demo UI, an admin tool, or a custom relayer). The application bytecode — and
/// thus this interface — cannot change after deployment, so every
/// [`BridgeOperation`] is exposed; on-chain authorization still gates each.
/// Byte-array arguments are hex-encoded strings (with or without `0x`).
pub struct MutationRoot {
runtime: Arc<ServiceRuntime<EvmBridgeService>>,
}
#[Object]
impl MutationRoot {
/// Burns `amount` wrapped tokens from the operation's authenticated signerView on GitHub (pinned to 6c226ddcb3)
Solutions
- Count the hex characters (after the optional 0x): it must be exactly 2N — 64 chars for 32-byte hashes/topics, 40 for 20-byte addresses — and match the field named in the message.
- If the value is short, left-pad with zeros to the required length; if long, verify you have the right value (e.g. a full keccak hash, not its truncated form).
- Double-check you are putting the value in the right argument (address vs hash vs topic) per the field's label in the message.
Example fix
// before // 32-byte field, but only 4 hex chars given topic: "0xabcd" // -> "topic must be exactly 32 bytes (64 hex chars)" // after topic: "0x000000000000000000000000000000000000000000000000000000000000abcd" // 64 hex chars
Defensive patterns
Strategy: validation
Validate before calling
fn has_hex_len(s: &str, n_bytes: usize) -> bool {
let body = s.strip_prefix("0x").unwrap_or(s);
body.len() == n_bytes * 2 && body.bytes().all(|b| b.is_ascii_hexdigit())
}
// e.g. has_hex_len(topic, 32) before sending it to the bridge service Type guard
fn is_32_byte_hex(s: &str) -> bool {
let body = s.strip_prefix("0x").unwrap_or(s);
body.len() == 64 && body.bytes().all(|b| b.is_ascii_hexdigit())
} Prevention
- Keep a per-field expected length table (address=20, txHash/topic=32) and assert before each request.
- Left-pad short values to the field width instead of hoping the server accepts them.
- Use typed client structs (e.g. alloy/primitive types H256/H160) that make wrong-length values unrepresentable.
When it happens
Trigger: Calling a bridge-service GraphQL field routed through decode_hex_array with a valid-hex string whose length is not 2N hex chars: e.g. a 40-hex-char (20-byte) EVM address where 64 hex chars (32 bytes) are required, a truncated hash, or an over-long value.
Common situations: Mixing up field types: passing an Ethereum address (20 bytes) as a transaction hash (32 bytes) or vice versa; using a topic hash without left-padding to 32 bytes; pasting a hash that lost leading zeros when converted through a decimal intermediate; confusing byte count with hex-char count (sending 32 hex chars thinking that is 32 bytes).
Related errors
- invalid {label} hex: {e}
- This user has no chain yet
- Request processing was cancelled
- invalid hex
- no errors present but no data returned
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/a1a2b91323b90bb2.
Report an issue: GitHub.