PQS 3.4.1 crashes when transcoding ACS to JSON

I’m on PQS 3.4.1 and I’m seeing this crash regarding the handling of Optional None on certain transactions relating to the JSON transcoding of DAML choice arguments/results. This happens regardless of the ledgerStart value because it is part of ACS.

06:36:50.405 I \[zio-fiber-1716526572\] com.digitalasset.zio.daml.ledgerapi.UpdateService:166 Converting transaction (ledger effects) 1220cc7f89b92354c3883d1a4e8e86f8519ce5845ce8b79f23b3b7bc87434d00f647 (offset: 992733, events: 5, remote trace: 1d81c79fcc4235c7bca1c9d5f0a626df)  trace_id=823450047ed52d30dcf5a2329a31b95f correlation_id=1d81c79fcc4235c7bca1c9d5f0a626df application=scribe
06:36:52.529 E \[zio-fiber-2111571141\] com.digitalasset.scribe.app.ComposableApp:66  Exception in thread “zio-fiber-548704253” java.lang.ClassCastException: class scala.None$ cannot be cast to class java.lang.String (scala.None$ is in unnamed module of loader ‘app’; java.lang.String is in module java.base of loader ‘bootstrap’)
at com.digitalasset.transcode.schema.DynamicValue$.party(DynamicValue.scala:148)
at com.digitalasset.transcode.codec.json.JsonCodec$$anon$16.fromDynamicValue(JsonCodec.scala:173)
at com.digitalasset.transcode.codec.json.JsonCodec$$anon$16.fromDynamicValue(JsonCodec.scala:173)
at com.digitalasset.transcode.codec.json.JsonCodec.com$digitalasset$transcode$codec$json$JsonCodec$$anon$1$$*$*$$anonfun$3(JsonCodec.scala:53)
at scala.collection.Iterator$$anon$9.next(Iterator.scala:584)
at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:619)
at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:617)
at scala.collection.AbstractIterator.foreach(Iterator.scala:1306)
at upickle.core.LinkedHashMap$.apply(LinkedHashMap.scala:53)
at ujson.Obj$.from(Value.scala:210)
at com.digitalasset.transcode.codec.json.JsonCodec$$anon$1.fromDynamicValue(JsonCodec.scala:55)
at com.digitalasset.transcode.codec.json.JsonCodec$$anon$1.fromDynamicValue(JsonCodec.scala:50)
at com.digitalasset.transcode.schema.CodecVisitor$$anon$2.fromDynamicValue(CodecVisitor.scala:26)
at com.digitalasset.transcode.schema.CodecVisitor$$anon$1.fromDynamicValue(CodecVisitor.scala:16)
at com.digitalasset.scribe.postgres.document.specific$Service.$anonfun$2(specific.scala:225)
at scala.collection.ArrayOps$.map$extension(ArrayOps.scala:936)
at zio.Chunk$Arr.mapChunk(Chunk.scala:1767)
at zio.ChunkLike.map(ChunkLike.scala:121)
at zio.ChunkLike.map$(ChunkLike.scala:39)
at zio.Chunk.map(Chunk.scala:42)
at com.digitalasset.scribe.postgres.document.specific$Service.insertEvent(specific.scala:214)
at com.digitalasset.scribe.postgres.document.specific$Service.insertEvent$(specific.scala:150)
at com.digitalasset.scribe.postgres.document.DocumentPostgres$Service.insertEvent(DocumentPostgres.scala:181)
at com.digitalasset.scribe.postgres.document.specific$Service.$anonfun$1(specific.scala:175)
at zio.ChunkLike.flatMap(ChunkLike.scala:78)
at zio.ChunkLike.flatMap$(ChunkLike.scala:39)
at zio.Chunk.flatMap(Chunk.scala:42)
at com.digitalasset.scribe.postgres.document.specific$Service.convertTransactionToSqlStatements(specific.scala:175)
at com.digitalasset.scribe.postgres.document.specific$Service.convertTransactionToSqlStatements$(specific.scala:150)
at com.digitalasset.scribe.postgres.document.DocumentPostgres$Service.convertTransactionToSqlStatements(DocumentPostgres.scala:181)
at com.digitalasset.scribe.postgres.document.DocumentPostgres$Service.convertTransactionEventsToStatements$$anonfun$1$$anonfun$1$$anonfun$1$$anonfun$1$$anonfun$1(DocumentPostgres.scala:276)
at zio.ZIOCompanionVersionSpecific.attempt$$anonfun$1(ZIOCompanionVersionSpecific.scala:108)
at zio.ZIO$.suspendSucceed$$anonfun$1(ZIO.scala:4823)
at com.digitalasset.scribe.postgres.document.DocumentPostgres.Service.convertTransactionEventsToStatements(DocumentPostgres.scala:276)
at com.digitalasset.scribe.postgres.document.DocumentPostgres.Service.convertTransactionEventsToStatements(DocumentPostgres.scala:278)
at com.digitalasset.scribe.postgres.document.DocumentPostgres.Service.convertTransactionEventsToStatements(DocumentPostgres.scala:279)
at com.digitalasset.scribe.postgres.document.DocumentPostgres.Service.convertTransactionEventsToStatements(DocumentPostgres.scala:280) application=scribe
java.lang.ClassCastException: class scala.None$ cannot be cast to class java.lang.String (scala.None$ is in unnamed module of loader ‘app’; java.lang.String is in module java.base of loader ‘bootstrap’)
\[diagnostics\] Diagnostics server shutting down now…
\[diagnostics\] Shutting down Micrometer to OpenMetrics bridge
\[diagnostics\] Shutting down thread dumps collector

Hello @kevmuko ,

PQS is reporting the error due to a mismatch between the Daml model it expects the contract payload to have versus the payload structure. Can you provide more details about the update causing this failure?

On the first log line you have the offset of the transaction causing this error which can help you query the Ledger API directly for it. Additionally, it would help if you provide the relevant Daml template of the contract created in that transaction.

1 Like

I think I have narrowed it down to a new non-Optional field we added to our TokenHolding template:

template TokenHolding
  with
    owner : Party
    instrumentId : InstrumentId
    amount : Decimal
    lock : Optional Lock
    featuredAppRightCid : Optional (ContractId FA.FeaturedAppRight)
    rewardBeneficiary : Party
40de54... │ 5 fields (owner, instrumentId, amount, lock, featuredAppRightCid
754014... │ 6 fields (+rewardBeneficiary)

There are still active contracts and historical transactions that refer to both schemas one with 5 / 6 fields and that is my guess at the root of the cause. Though I’m not sure why this would be happening if PQS were to decode by package_id instead of the template qualified name (which would map to the newer 6 field schema).

Hi @kevmuko ,

The decode failure is indeed unexplained since it should done by package-id as you remarked. What is the package-id of the CreatedEvent.templateId associated with the contract whose decoding crashes? Is it from the package without rewardBeneficiary (40de54) or the one with (754014)?

Another question: is this a PQS instance with a pre-populated DB or is this started from scratch?

Hi @kevmuko,

We have released a new PQS version that fixes the issue you observed: PQS interface view bug and deployment model change in Canton 3.4 . Hopefully, this solves the problem for you as well.