Limits and errors
Limits
| What | Limit |
|---|---|
| QR frames per scan | 2,048 (BBQr: 1,295) |
| Characters per frame | 4,300 |
| Scanned text kept per session | 1 MiB |
| Decoded payload (CBOR or PSBT) | 128 KiB |
| CBOR nesting / items | 24 levels / 20,000 items |
| Wallet-level pairing payload (produced) | 4,096 bytes |
| Request ID | 16 bytes (eth-sign-request: 1–64) |
| Origin | 256 characters |
| Bitcoin inputs and outputs | 1–100 each |
| EVM calldata | 64 KiB |
| EVM personal message | 1–8,192 bytes |
| EIP-712 | 32 types, 64 fields per type, arrays up to 128 items |
| TRON message | 1–8,192 bytes |
| Solana message (sign-type 2) | 1–1,024 bytes of UTF-8 text |
| Solana transaction | 1–64 instructions, 1,232-byte packet |
Common rejections
When BitTool Signer refuses a request it shows a short message in the scanner or on the review screen. These are the ones integrators hit most often:
| Message | Cause | Fix |
|---|---|---|
| Unsupported signing UR type | The UR type is not one of crypto-psbt, psbt, eth-sign-request, sol-sign-request, tron-sign-request | Use the public registry types; a pairing QR code cannot be signed |
| Unsupported signing request field | A map key outside 1–7 (ETH) or 1–6 (SOL/TRON) | Remove custom fields |
| Invalid request UUID tag / requestId has invalid length | Request ID not wrapped in tag 37, or not 16 bytes for SOL/TRON | 37(16 random bytes) |
| Signing path must be concrete | A * wildcard, an empty child, or an index ≥ 231 | Send the full leaf path with true/false hardened flags |
| Transaction data type does not match payload | data-type 1 with a typed transaction, or 4 with legacy RLP | 1 for legacy RLP, 4 for 0x01/0x02 envelopes |
| Unprotected or missing-chain-ID EVM transactions are refused | Legacy transaction without EIP-155 chain ID | Serialize with the chain ID (v = chainId, r = s = 0) |
| Chain ID does not match the signing request | Transaction, key 4 and/or EIP-712 domain disagree | Make all chain IDs equal |
| Unsupported network | Chain ID outside the eight supported EVM networks, or a non-mainnet request | Use a supported network |
| Typed message has extra unsigned or missing fields | message fields differ from the declared type | Send exactly the declared fields |
| Use strings for large typed integers | A JSON number above 253 in EIP-712 data | Encode it as a decimal string |
| Full previous transactions (nonWitnessUtxo) are required … | SegWit v0 or legacy input without nonWitnessUtxo | Add the full previous transaction |
| Only SIGHASH_ALL or Taproot SIGHASH_DEFAULT is accepted | Another sighash type on an input | Use SIGHASH_ALL |
| No unsigned input belongs to this wallet … | No input with a bip32Derivation for this wallet's key | Add derivation data with the right fingerprint and path |
| Exactly one TRON contract is supported per transaction | raw_data.contract has 0 or several entries | One contract per transaction |
| TRON contract calls require an explicit fee limit | TriggerSmartContract without fee_limit | Set fee_limit |
| Invalid TRON timestamp or expiration | Missing timestamp, or expiration ≤ timestamp | Use the values from your node |
| Address lookup tables require independently trusted account data … | v0 Solana message with lookup tables | Compile with static account keys |
| This wallet is not a required signer in the transaction | Key 4 is not among the message's required signers | Use the account that must sign |
| Solana message prefix could represent a transaction header | sign-type 2 used for bytes that look like a transaction | Use sign-type 1 for transactions |
| Mixed UR fountain sessions / Multiple unrelated QR payloads | Frames from two different QR codes in one scan | Show one request at a time |
Error texts come only from the engine's own checks. Unexpected exceptions are reported as a generic error, so a malicious payload cannot inject text into the signer's interface.
Matching results
Before the password prompt, the request is matched to the wallets on the phone. Only ready can be signed:
| Status | Meaning |
|---|---|
ready | Exactly one wallet holds the key; the signing tasks are fixed |
noMatch | No wallet on this phone has the requested key (wrong fingerprint or path, or the wallet is not imported) |
missingSigner | The request does not say which key should sign (no derivation data, no address) |
ambiguous | More than one wallet fits, for example the same phrase imported twice |
setupRequired | A wallet's public data needs to be rebuilt (one password entry) |
invalid | The request is structurally invalid |