canopy-network/canopy · error · ErrInvalidRLPTx

ErrInvalidRLPTx

ErrInvalidRLPTx

Error message

max transaction size

What it means

rlpToCanopyTransaction enforces an anti-spam cap: the raw RLP-encoded Ethereum transaction must be at most 2 KB. Larger payloads are rejected as ErrInvalidRLPTx('max transaction size') before decoding.

Source

Thrown at fsm/ethereum.go:79

		return nil, ErrInvalidRLPTx(err)
	}
	return tx.Hash().Bytes(), nil
}

// RLPToCanopyTransaction() converts a legacy-domain RLP transaction into a Canopy transaction.
func RLPToCanopyTransaction(txBytes []byte) (transaction *lib.Transaction, e lib.ErrorI) {
	return rlpToCanopyTransaction(txBytes, RLPIndicator)
}

// RLPToCanopyTransactionV2() converts an RLP encoded transaction into a nonce-backed Canopy transaction.
func RLPToCanopyTransactionV2(txBytes []byte) (transaction *lib.Transaction, e lib.ErrorI) {
	return rlpToCanopyTransaction(txBytes, RLPV2Indicator)
}

func rlpToCanopyTransaction(txBytes []byte, memo string) (transaction *lib.Transaction, e lib.ErrorI) {
	// protect against spam
	if len(txBytes) > int(2*units.KB) {
		return nil, ErrInvalidRLPTx(fmt.Errorf("max transaction size"))
	}
	// decode transaction to ethereum object
	var tx ethTypes.Transaction
	if err := tx.UnmarshalBinary(txBytes); err != nil {
		return nil, ErrInvalidRLPTx(err)
	}
	// get the signer type (supports: Legacy, EIP-155, EIP-1559, EIP-2930, EIP-4844, EIP-7702)
	signer := ethTypes.LatestSignerForChainID(tx.ChainId())
	// recover the public key from the rlp transaction and validate the signature
	publicKey, err := crypto.RecoverPublicKey(signer, tx)
	if err != nil {
		return nil, ErrInvalidPublicKey(err)
	}
	// ensure the EVM chain id fits into Canopy's uint64 translation.
	if tx.ChainId() == nil || !tx.ChainId().IsUint64() {
		return nil, ErrInvalidRLPTx(fmt.Errorf("chain id exceeds uint64"))
	}
	// The signed Ethereum chain ID separates legacy RLP from RLP.V2 even while

View on GitHub (pinned to ee8197d91d)

Solutions

  1. Reduce the transaction payload size (trim data/calldata) below 2048 bytes before submission
  2. Split large operations into multiple transactions
  3. Check whether extra data is being accidentally appended to the RLP encoding
  4. If legitimate use needs more space, this is a protocol limit — file/track a protocol change rather than bypassing it

Example fix

// before
if len(txBytes) > 4096 { submit(txBytes) } // exceeds 2KB cap
// after
if len(txBytes) > int(2*units.KB) {
    return fmt.Errorf("tx is %d bytes; RLP tx limit is 2048 bytes", len(txBytes))
}
submit(txBytes)
Defensive patterns

Strategy: validation

Validate before calling

const maxRLPTx = 2 * 1024
if len(txBytes) > maxRLPTx {
    return fmt.Errorf("tx %d bytes exceeds %d byte RLP limit", len(txBytes), maxRLPTx)
}

Type guard

func fitsRLPLimit(b []byte) bool { return len(b) <= 2*1024 }

Try / catch

tx, err := fsm.RLPToCanopyTransaction(bz)
if err != nil {
    if strings.Contains(err.Error(), "max transaction size") {
        return nil, fmt.Errorf("reduce payload to under 2048 bytes")
    }
    return err
}

Prevention

When it happens

Trigger: Submitting an RLP transaction (RLPToCanopyTransaction or RLPToCanopyTransactionV2) whose serialized bytes exceed 2*units.KB (2048 bytes), e.g. transactions carrying large calldata via tx.Data().

Common situations: Bridging Ethereum transactions with big memo/extraData payloads, contract-interaction blobs that exceed the cap, or malicious spam transactions crafted to bloat block space.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of canopy-network/canopy@ee8197d91d (2026-09-06). Data as JSON: /api/errors/5c0a9c863339f676. Report an issue: GitHub.