Mensaje de error
Unexpected recoverable signature length: Expected 65, but got 64 bytes
También se muestra como
- eth_utils.exceptions.ValidationError: Unexpected recoverable signature length: Expected 65, but got 64 bytes
El número de bytes que sigue a «but got» es la longitud de tu firma. La clase de la excepción es `eth_utils.exceptions.ValidationError`.
web3.py / eth-account / eth-keys (Python) — eth_utils.exceptions.ValidationError from Account.recover_message
Qué significa
eth-keys (que usan eth-account y web3.py) solo construye una firma recuperable a partir de exactamente 65 bytes: r (32), s (32) y el byte de recuperación v. La firma que pasas tiene otra longitud —en este caso, 64 bytes—, así que la recuperación no pudo empezar. `w3.eth.account.recover_message` de web3.py lanza el mismo error, porque delega en eth-account.
Por qué ocurre
v se guardó por separado o se perdió
frecuenteLos backends que guardan columnas `r` y `s`, o los frontends que recortan la firma, pierden el último byte. Sin v, la clave pública no se puede recuperar de forma inequívoca.
Una firma compacta EIP-2098
ocasionalLas firmas compactas de 64 bytes integran el bit de recuperación en el bit más alto de s. eth-account no las acepta directamente.
Texto hex pasado como bytes
ocasionalPasar `signature_hex.encode()` da 132 bytes de ASCII en lugar de 65 bytes de firma. Pasa la propia cadena hex o `bytes.fromhex(...)` sin el `0x`.
Cómo solucionarlo
- 1.
Pasar la firma completa tal como la devuelve la billetera
`personal_sign` / `eth_signTypedData_v4` devuelven una cadena hex de 65 bytes; mantenla intacta de principio a fin.
python from eth_account import Account from eth_account.messages import encode_defunct # Pass the 0x-prefixed hex string exactly as the wallet returned it (132 hex chars + "0x"). signer = Account.recover_message(encode_defunct(text=message), signature=signature_hex) assert signer.lower() == expected_address.lower() - 2.
Expandir las firmas compactas
Separa yParity del bit más alto de la segunda mitad y añade al final v = 27 + yParity.
python def expand_eip2098(sig: bytes) -> bytes: """64-byte compact signature (r || yParityAndS) -> 65-byte r || s || v.""" r, ys = sig[:32], int.from_bytes(sig[32:], "big") y_parity = ys >> 255 s = ys & ((1 << 255) - 1) return r + s.to_bytes(32, "big") + bytes([27 + y_parity])