RES: [corda-dev] #Corda Unable to process a transaction containing big amount of states due to exceeded message size limit #Corda


Hi, Oleksandra,


Hope you are doing fine?

If you are the owner of the network, maybe you can raise the maxMessageSize and the maxTransactionSize network parameters:


  • maxMessageSize: Maximum allowed size in bytes of an individual message sent over the wire. Note that attachments are a special case and may be fragmented for streaming transfer, however, an individual transaction or flow message may not be larger than this value.
  • maxTransactionSize: Maximum allowed size in bytes of a transaction. This is the size of the transaction object and its attachments.

Anyway, are all these states and obligations from the same Parties in this big transaction? If they are not, you might be leaking some confidential information, since in order to validate the transaction, the receiving partner will have to check de dependency chain of thousands of states.


Best regards,



4251 / Departamento de Pesquisa e Inovação

Pesquisas Especiais

George Marcel M. A. Smetana

Tel.: 11 3684-8460, ramal: (2)48460 – Fax: 11 3684-8351

mailto: george.smetana@...


Attachments are limited to 2MB


De: <> Em nome de oleksandra@...
Enviada em: quinta-feira, 22 de outubro de 2020 04:31
Assunto: [corda-dev] #Corda Unable to process a transaction containing big amount of states due to exceeded message size limit


Hi guys,
we've faced an issue that during the CollectionSignatures and Finalization of the transaction the net.corda.nodeapi.internal.ArtemisUtils will throw an error:

Message exceeds maxMessageSize network parameter, maxMessageSize: [10485760] when the number of the states in one transaction is big.

I understand that this is a logical/robust check on the ArtemisMQ side since as more bytes 1 message contains - more chances to fail during the network transmission.
The questions and details of this topic are more related to:

  • Could anyone provide information on what is the best way/practice in Corda API of handling such scenarios of a big amount of states and still has a transactional flow? 
  • Can we somehow send the states in subflows, but finalize them only in the parent flow?
  • Is there any way of sending the states in 1 transaction by parts(chunks) or as a stream to prevent exceeding the limits but still have the transactional flow?

I'll try to describe the details with code examples of the issue:

Use case: we have the states which represents obligations (Obligation State), and the state that represents a payment. One payment state can cover multiple obligations and settle them. So the structure of the Payment is:


    data class PaymentState(

    val paymentItems: List<PaymentItem>,

    override val linearId: UniqueIdentifier = UniqueIdentifier()

    ) : LinearState, QueryableState { ... }


    data class PaymentItem(

    val id: UUID = UUID.randomUUID(),

    val obligationId: UUID,

    val amount: Amount

    ) // not a state just a child


    data class ObligationState(

    val amount: Amount, // initial obligation amount

    val availableAmount, // initially = remaining/settled/paid amount, and will be reduced when be payed/settled 

    override val linearId: UniqueIdentifier = UniqueIdentifier()

    ) : LinearState, QueryableState { ... }


The user1 creates 1000 obligations during the month (not a single operation)
The user2 pays for 1000 obligations and wants to do it in one transaction.

One corda transaction can be described like this:

 - Input State and Refs - 1000 obligation state&refs (prev versions)

 - Output States - 1000 obligation states with updated money (states that have to be updated), 1 Payment State (state that has to be created)


So the described example contains a lot of states in the same transaction which leads us to have a huge message to be sent to another party. And potentially have a situation when the message will exceed its limit (for example if the Payment was raised to cover more states ~1300 will exceed the limit).


So we've tried to think about diving this transaction into multiple small parts. But faced that if we do it separately it will lead to the situation when one of them possibly can fail, since the others were Finalized they can't be rollbacked, since it's no more than 1 transaction that can be rollbacked if smth happened.  


Please find the code in the attachment PaymentCreateDemo.kts (not actual, simplified one, in order to reflect the work with states, flows, subflows). The first attempt of resolving msg limits error.


The dividing into pieces we've done in two approaches, firstly we've tried to update the ObligationStates chunked them by 500 in one tx (each tx processing in the subflow separately), and when all txs completed it's ready to create a PaymentState in another tx. This has two drawbacks, 1st it's no more than 1 transaction and the rollback of prev txs is impossible, the 2nd - PaymentState can have any number of PaymentItems and if it's approximately 86.000 it will exceed the limit of message size too.


The second approach was to have an additional state to aggregate the PaymentItems in groups. Each group has a max size=500 of items. So if it's 1000 items it will be divided into 2 groups for 1 payment. This resolved the issue of the second drawback described in a prev paragraph.


    data class PaymentState(

    override val linearId: UniqueIdentifier = UniqueIdentifier(),

    val version: Int

    // no more contains items

    ) : LinearState, QueryableState { ... }


    data class PaymentItemGroup(

    val paymentStateId: UUID, // check always the head state

    val paymentItems: List<PaymentItem>,

    override val linearId: UniqueIdentifier = UniqueIdentifier()

    ) : LinearState, QueryableState { ... }


I've attached schemas describing the sequential processing of the subflows and parallel one - to speed up the sharing process.

But still, we have a situation when one of the transactions will fail and only part of the actual payment was reflected as paid/settled on obligations.



...Esta mensagem é destinada exclusivamente para a(s) pessoa(s) a quem é dirigida, podendo conter informação confidencial e/ou legalmente privilegiada. Se você não for destinatário desta mensagem, desde já fica notificado de abster-se a divulgar, copiar, distribuir, examinar ou, de qualquer forma, utilizar a informação contida nesta mensagem, por ser ilegal. Caso você tenha recebido esta mensagem por engano, pedimos que nos retorne este E-Mail, promovendo, desde logo, a eliminação do seu conteúdo em sua base de dados, registros ou sistema de controle. Fica desprovida de eficácia e validade a mensagem que contiver vínculos obrigacionais, expedida por quem não detenha poderes de representação. LEGAL ADVICE
...This message is exclusively destined for the people to whom it is directed, and it can bear private and/or legally exceptional information. If you are not addressee of this message, since now you are advised to not release, copy, distribute, check or, otherwise, use the information contained in this message, because it is illegal. If you received this message by mistake, we ask you to return this email, making possible, as soon as possible, the elimination of its contents of your database, registrations or controls system. The message that bears any mandatory links, issued by someone who has no representation powers, shall be null or void.


On Fri, Oct 23, 2020 at 12:02 AM, GEORGE MARCEL MONTEIRO ARCURI SMETANA wrote:
are all these states and obligations from the same Parties in this big transaction?

Hi George, thank you for your answer, yes all the states correspond to the same parties. That's just such a requirement of the use case, cover transactionally in one payment many obligations.

you can raise the maxMessageSize and the maxTransactionSize network parameters

The default values are:
const val DEFAULT_MAX_MESSAGE_SIZE: Int = 10485760 // ~10mb
const val DEFAULT_MAX_TRANSACTION_SIZE: Int = 524288000 // ~50mb
I guess that's not recommended to increase these values, plus later it won't be a private network, but cordite.
That's why in this topic I'm trying to find help to understand is it possible in Corda to divide data but still do it transactionally.