We're updating the issue view to help you get more done. 

Provide a better error message on an incompatible implicit contract upgrade

Description

When using signature constraints and implicit contract upgrades, if the upgraded version is incompatible with the older version (e.g. a new non-nullable field is added), a deserialization error occurs when trying to load an old state with the new version of the app.

For example:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 Caused by: net.corda.core.node.services.VaultQueryException: An error occurred while attempting to query the vault: Failed to deserialise group OUTPUTS_GROUP at index 0 in transaction: Cannot construct evolution serializer for remote type net.corda.finance.contracts.asset.Cash$State: net.corda.core.contracts.FungibleAsset<java.util.Currency>, net.corda.core.contracts.FungibleState<net.corda.core.contracts.Issued<java.util.Currency>>, net.corda.core.contracts.ContractState, net.corda.core.contracts.OwnableState, net.corda.core.schemas.QueryableState amount: net.corda.core.contracts.Amount<net.corda.core.contracts.Issued<java.util.Currency>> displayTokenSize: java.math.BigDecimal quantity: long token: net.corda.core.contracts.Issued<java.util.Currency> issuer: net.corda.core.contracts.PartyAndReference party: net.corda.core.identity.AbstractParty owningKey: java.security.PublicKey reference: net.corda.core.utilities.OpaqueBytes bytes: byte[] product: java.util.Currency exitKeys: java.util.Collection<java.security.PublicKey> owner: net.corda.core.identity.AbstractParty owningKey: java.security.PublicKey Mandatory property upgradedState of local type is not present in remote type - did someone remove a property from the schema without considering old clients? at net.corda.node.services.vault.NodeVaultService._queryBy(NodeVaultService.kt:519) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.CordaRPCOpsImpl.vaultQueryBy(CordaRPCOpsImpl.kt:108) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.CordaRPCOpsImpl.vaultQuery(CordaRPCOpsImpl.kt:264) ~[corda-node-4.0-RC05.jar:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_202] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_202] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_202] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_202] at net.corda.node.internal.InvocationHandlerTemplate$DefaultImpls.invoke(InvocationHandlerTemplate.kt:16) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler$invoke$1.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:52) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:46) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.access$guard(AuthenticatedRpcOpsProxy.kt:1) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?] ... 42 more Caused by: net.corda.core.internal.TransactionDeserialisationException: Failed to deserialise group OUTPUTS_GROUP at index 0 in transaction: Cannot construct evolution serializer for remote type net.corda.finance.contracts.asset.Cash$State: net.corda.core.contracts.FungibleAsset<java.util.Currency>, net.corda.core.contracts.FungibleState<net.corda.core.contracts.Issued<java.util.Currency>>, net.corda.core.contracts.ContractState, net.corda.core.contracts.OwnableState, net.corda.core.schemas.QueryableState amount: net.corda.core.contracts.Amount<net.corda.core.contracts.Issued<java.util.Currency>> displayTokenSize: java.math.BigDecimal quantity: long token: net.corda.core.contracts.Issued<java.util.Currency> issuer: net.corda.core.contracts.PartyAndReference party: net.corda.core.identity.AbstractParty owningKey: java.security.PublicKey reference: net.corda.core.utilities.OpaqueBytes bytes: byte[] product: java.util.Currency exitKeys: java.util.Collection<java.security.PublicKey> owner: net.corda.core.identity.AbstractParty owningKey: java.security.PublicKey Mandatory property upgradedState of local type is not present in remote type - did someone remove a property from the schema without considering old clients? at net.corda.core.internal.TransactionUtilsKt$deserialiseComponentGroup$1.invoke(TransactionUtils.kt:82) ~[corda-core-4.0-RC05.jar:?] at net.corda.core.internal.TransactionUtilsKt$deserialiseComponentGroup$1.invoke(TransactionUtils.kt) ~[corda-core-4.0-RC05.jar:?] at net.corda.core.internal.LazyMappedList.get(InternalUtils.kt:533) ~[corda-core-4.0-RC05.jar:?] at net.corda.node.internal.ServicesForResolutionImpl.loadStates(ServicesForResolutionImpl.kt:38) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.services.vault.NodeVaultService$_queryBy$2.invoke(NodeVaultService.kt:604) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.services.vault.NodeVaultService$_queryBy$2.invoke(NodeVaultService.kt:55) ~[corda-node-4.0-RC05.jar:?] at net.corda.nodeapi.internal.persistence.CordaPersistence.inTopLevelTransaction(CordaPersistence.kt:236) ~[corda-node-api-4.0-RC05.jar:?] at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:221) ~[corda-node-api-4.0-RC05.jar:?] at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:199) ~[corda-node-api-4.0-RC05.jar:?] at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:205) ~[corda-node-api-4.0-RC05.jar:?] at net.corda.node.services.vault.NodeVaultService._queryBy(NodeVaultService.kt:526) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.services.vault.NodeVaultService._queryBy(NodeVaultService.kt:515) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.CordaRPCOpsImpl.vaultQueryBy(CordaRPCOpsImpl.kt:108) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.CordaRPCOpsImpl.vaultQuery(CordaRPCOpsImpl.kt:264) ~[corda-node-4.0-RC05.jar:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_202] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_202] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_202] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_202] at net.corda.node.internal.InvocationHandlerTemplate$DefaultImpls.invoke(InvocationHandlerTemplate.kt:16) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler$invoke$1.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:52) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:46) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.access$guard(AuthenticatedRpcOpsProxy.kt:1) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?] ... 42 more Caused by: net.corda.serialization.internal.amqp.EvolutionSerializationException: Cannot construct evolution serializer for remote type net.corda.finance.contracts.asset.Cash$State: net.corda.core.contracts.FungibleAsset<java.util.Currency>, net.corda.core.contracts.FungibleState<net.corda.core.contracts.Issued<java.util.Currency>>, net.corda.core.contracts.ContractState, net.corda.core.contracts.OwnableState, net.corda.core.schemas.QueryableState amount: net.corda.core.contracts.Amount<net.corda.core.contracts.Issued<java.util.Currency>> displayTokenSize: java.math.BigDecimal quantity: long token: net.corda.core.contracts.Issued<java.util.Currency> issuer: net.corda.core.contracts.PartyAndReference party: net.corda.core.identity.AbstractParty owningKey: java.security.PublicKey reference: net.corda.core.utilities.OpaqueBytes bytes: byte[] product: java.util.Currency exitKeys: java.util.Collection<java.security.PublicKey> owner: net.corda.core.identity.AbstractParty owningKey: java.security.PublicKey Mandatory property upgradedState of local type is not present in remote type - did someone remove a property from the schema without considering old clients? at net.corda.serialization.internal.amqp.DefaultEvolutionSerializerFactory.validateEvolvability(EvolutionSerializerFactory.kt:110) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultEvolutionSerializerFactory.getEvolutionSerializer(EvolutionSerializerFactory.kt:65) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultEvolutionSerializerFactory.getEvolutionSerializer(EvolutionSerializerFactory.kt:40) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory.getUncached(RemoteSerializerFactory.kt:99) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory.access$getUncached(RemoteSerializerFactory.kt:47) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory$get$1$$special$$inlined$mapValues$lambda$1.invoke(RemoteSerializerFactory.kt:73) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory$get$1$$special$$inlined$mapValues$lambda$1.invoke(RemoteSerializerFactory.kt:47) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultDescriptorBasedSerializerRegistry.getOrBuild(DescriptorBasedSerializerRegistry.kt:28) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory$get$1.invoke(RemoteSerializerFactory.kt:72) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory$get$1.invoke(RemoteSerializerFactory.kt:47) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultDescriptorBasedSerializerRegistry.getOrBuild(DescriptorBasedSerializerRegistry.kt:28) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory.get(RemoteSerializerFactory.kt:62) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.ComposedSerializerFactory.get(SerializerFactory.kt) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DeserializationInput.readObject$serialization(DeserializationInput.kt:172) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DeserializationInput.readObjectOrNull$serialization(DeserializationInput.kt:147) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DeserializationInput$deserialize$1.invoke(DeserializationInput.kt:124) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DeserializationInput.des(DeserializationInput.kt:99) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.DeserializationInput.deserialize(DeserializationInput.kt:119) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme.deserialize(AMQPSerializationScheme.kt:225) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.SerializationFactoryImpl$deserialize$1$1.invoke(SerializationScheme.kt:102) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.core.serialization.SerializationFactory.withCurrentContext(SerializationAPI.kt:72) ~[corda-core-4.0-RC05.jar:?] at net.corda.serialization.internal.SerializationFactoryImpl$deserialize$1.invoke(SerializationScheme.kt:102) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.serialization.internal.SerializationFactoryImpl$deserialize$1.invoke(SerializationScheme.kt:70) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.core.serialization.SerializationFactory.asCurrent(SerializationAPI.kt:86) ~[corda-core-4.0-RC05.jar:?] at net.corda.serialization.internal.SerializationFactoryImpl.deserialize(SerializationScheme.kt:102) ~[corda-serialization-4.0-RC05.jar:?] at net.corda.core.internal.TransactionUtilsKt$deserialiseComponentGroup$1.invoke(TransactionUtils.kt:78) ~[corda-core-4.0-RC05.jar:?] at net.corda.core.internal.TransactionUtilsKt$deserialiseComponentGroup$1.invoke(TransactionUtils.kt) ~[corda-core-4.0-RC05.jar:?] at net.corda.core.internal.LazyMappedList.get(InternalUtils.kt:533) ~[corda-core-4.0-RC05.jar:?] at net.corda.node.internal.ServicesForResolutionImpl.loadStates(ServicesForResolutionImpl.kt:38) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.services.vault.NodeVaultService$_queryBy$2.invoke(NodeVaultService.kt:604) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.services.vault.NodeVaultService$_queryBy$2.invoke(NodeVaultService.kt:55) ~[corda-node-4.0-RC05.jar:?] at net.corda.nodeapi.internal.persistence.CordaPersistence.inTopLevelTransaction(CordaPersistence.kt:236) ~[corda-node-api-4.0-RC05.jar:?] at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:221) ~[corda-node-api-4.0-RC05.jar:?] at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:199) ~[corda-node-api-4.0-RC05.jar:?] at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:205) ~[corda-node-api-4.0-RC05.jar:?] at net.corda.node.services.vault.NodeVaultService._queryBy(NodeVaultService.kt:526) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.services.vault.NodeVaultService._queryBy(NodeVaultService.kt:515) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.CordaRPCOpsImpl.vaultQueryBy(CordaRPCOpsImpl.kt:108) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.CordaRPCOpsImpl.vaultQuery(CordaRPCOpsImpl.kt:264) ~[corda-node-4.0-RC05.jar:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_202] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_202] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_202] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_202] at net.corda.node.internal.InvocationHandlerTemplate$DefaultImpls.invoke(InvocationHandlerTemplate.kt:16) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler$invoke$1.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:52) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.guard(AuthenticatedRpcOpsProxy.kt:46) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxyKt.access$guard(AuthenticatedRpcOpsProxy.kt:1) ~[corda-node-4.0-RC05.jar:?] at net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy$PermissionsEnforcingInvocationHandler.invoke(AuthenticatedRpcOpsProxy.kt:42) ~[corda-node-4.0-RC05.jar:?] ... 42 more

For user this exception message is very cryptic and does not explain what the root cause can be.

Status

Assignee

James Higgs

Reporter

Andrius Dagys

Priority

Medium

Labels

None

Severity

Medium

Fix versions

Ported to...

None

Feature Team

Corda Core

Affects versions

Corda 4 RC05