Running the -native redrive, and while it appears to succeed, it crashes immediately afterwards with the following logs:
12:56:41.212 [elasticmq-pekko.actor.default-dispatcher-11] INFO o.a.pekko.actor.DeadLetterActorRef - Message [org.elasticmq.MessageData] to Actor[pekko://elasticmq/deadLetters] was not delivered. [1] dead letters encountered. If this is not an expected behavior then Actor[pekko://elasticmq/deadLetters] may have terminated unexpectedly. This logging can be turned off or adjusted with configuration settings 'pekko.log-dead-letters' and 'pekko.log-dead-letters-during-shutdown'.
Uncaught error from thread [elasticmq-pekko.actor.default-dispatcher-13]: null, shutting down JVM since 'pekko.jvm-exit-on-fatal-error' is enabled for ActorSystem[elasticmq]
java.lang.ExceptionInInitializerError
at org.elasticmq.rest.sqs.ListMessageMoveTasksDirectives.$anonfun$listMessageMoveTasks$1(ListMessageMoveTasksDirectives.scala:18)
at org.apache.pekko.http.scaladsl.server.Directive$.$anonfun$addByNameNullaryApply$2(Directive.scala:184)
at org.apache.pekko.http.scaladsl.server.Directive$.$anonfun$Empty$1(Directive.scala:170)
at org.apache.pekko.http.scaladsl.server.Directive$$anon$1.tapply(Directive.scala:165)
at org.apache.pekko.http.scaladsl.server.Directive$.$anonfun$addByNameNullaryApply$1(Directive.scala:184)
at org.elasticmq.rest.sqs.ListMessageMoveTasksDirectives.listMessageMoveTasks(ListMessageMoveTasksDirectives.scala:17)
at org.elasticmq.rest.sqs.ListMessageMoveTasksDirectives.listMessageMoveTasks$(ListMessageMoveTasksDirectives.scala:16)
at org.elasticmq.rest.sqs.TheSQSRestServerBuilder$$anon$1.listMessageMoveTasks(SQSRestServerBuilder.scala:153)
at org.elasticmq.rest.sqs.TheSQSRestServerBuilder.rawRoutes$1(SQSRestServerBuilder.scala:230)
at org.elasticmq.rest.sqs.TheSQSRestServerBuilder.$anonfun$start$8(SQSRestServerBuilder.scala:255)
at org.elasticmq.rest.sqs.directives.AnyParamDirectives.$anonfun$anyParamsMap$3(AnyParamDirectives.scala:76)
at org.apache.pekko.http.scaladsl.server.util.ApplyConverterInstances$$anon$1.$anonfun$apply$1(ApplyConverterInstances.scala:23)
at org.apache.pekko.http.scaladsl.server.ConjunctionMagnet$$anon$2.$anonfun$apply$3(Directive.scala:255)
at org.apache.pekko.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRouteResult$2(BasicDirectives.scala:80)
at org.apache.pekko.http.scaladsl.server.directives.FutureDirectives.$anonfun$onComplete$3(FutureDirectives.scala:47)
at org.apache.pekko.http.scaladsl.util.FastFuture$.$anonfun$transformWith$1(FastFuture.scala:45)
at org.apache.pekko.http.scaladsl.util.FastFuture$.strictTransform$1(FastFuture.scala:49)
at org.apache.pekko.http.scaladsl.util.FastFuture$.$anonfun$transformWith$3(FastFuture.scala:59)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:517)
at org.apache.pekko.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:72)
at org.apache.pekko.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:109)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:94)
at org.apache.pekko.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:109)
at org.apache.pekko.dispatch.TaskInvocation.run(AbstractDispatcher.scala:59)
at org.apache.pekko.dispatch.ForkJoinExecutorConfigurator$PekkoForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:62)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:704)
at com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:202)
Caused by: scala.MatchError: [Ljava.lang.String;@37928abb (of class [Ljava.lang.String;)
at spray.json.ProductFormatsInstances.jsonFormat2(ProductFormatsInstances.scala:46)
at spray.json.ProductFormatsInstances.jsonFormat2$(ProductFormatsInstances.scala:45)
at spray.json.DefaultJsonProtocol$.jsonFormat2(DefaultJsonProtocol.scala:30)
at org.elasticmq.rest.sqs.ListMessageMoveTasksRequest$.<clinit>(ListMessageMoveTasksDirectives.scala:53)
... 33 more
12:56:41.216 [elasticmq-pekko.actor.default-dispatcher-9] ERROR o.apache.pekko.actor.ActorSystemImpl - Uncaught error from thread [elasticmq-pekko.actor.default-dispatcher-13]: null, shutting down JVM since 'pekko.jvm-exit-on-fatal-error' is enabled for ActorSystem[elasticmq]
java.lang.ExceptionInInitializerError: null
at org.elasticmq.rest.sqs.ListMessageMoveTasksDirectives.$anonfun$listMessageMoveTasks$1(ListMessageMoveTasksDirectives.scala:18)
at org.apache.pekko.http.scaladsl.server.Directive$.$anonfun$addByNameNullaryApply$2(Directive.scala:184)
at org.apache.pekko.http.scaladsl.server.Directive$.$anonfun$Empty$1(Directive.scala:170)
at org.apache.pekko.http.scaladsl.server.Directive$$anon$1.tapply(Directive.scala:165)
at org.apache.pekko.http.scaladsl.server.Directive$.$anonfun$addByNameNullaryApply$1(Directive.scala:184)
at org.elasticmq.rest.sqs.ListMessageMoveTasksDirectives.listMessageMoveTasks(ListMessageMoveTasksDirectives.scala:17)
at org.elasticmq.rest.sqs.ListMessageMoveTasksDirectives.listMessageMoveTasks$(ListMessageMoveTasksDirectives.scala:16)
at org.elasticmq.rest.sqs.TheSQSRestServerBuilder$$anon$1.listMessageMoveTasks(SQSRestServerBuilder.scala:153)
at org.elasticmq.rest.sqs.TheSQSRestServerBuilder.rawRoutes$1(SQSRestServerBuilder.scala:230)
at org.elasticmq.rest.sqs.TheSQSRestServerBuilder.$anonfun$start$8(SQSRestServerBuilder.scala:255)
Claude is pretty certain this is a native graal vm problem - I've not worked with java in... 6(?) years now, so not much of an ability to dive straight into it anymore. I did have it produce this - hopefully it's useful to you. Apologies if the use of an LLM is inappropriate here - I didn't set it trying to find bugs, just as a diagnostic tool when I encountered this - here's its full output:
**Symptom:** Any `StartMessageMoveTask` (DLQ redrive) request terminates the whole
server. The move itself completes (messages are persisted to the destination queue),
but the action handler throws during class initialization, and because
`pekko.jvm-exit-on-fatal-error` is enabled the JVM exits — so the container dies and
must be restarted. On the JVM image the same request works normally.
**Stack trace (native, 1.7.1):**
java.lang.ExceptionInInitializerError
at org.elasticmq.rest.sqs.StartMessageMoveTaskDirectives.$anonfun$startMessageMoveTask$1(StartMessageMoveTaskDirectives.scala:21)
...
Caused by: scala.MatchError: [Ljava.lang.String;@... (of class [Ljava.lang.String;)
at spray.json.ProductFormatsInstances.jsonFormat3(ProductFormatsInstances.scala:68)
at spray.json.DefaultJsonProtocol$.jsonFormat3(DefaultJsonProtocol.scala:30)
at org.elasticmq.rest.sqs.StartMessageMoveTaskActionRequest$.<clinit>(StartMessageMoveTaskDirectives.scala:74)
**Root cause:**
`rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/StartMessageMoveTaskDirectives.scala`
derives the JSON format for the 3-field `StartMessageMoveTaskActionRequest` with the
no-field-names `jsonFormat3(...)`. That overload calls spray-json's reflective
`extractFieldNames`, then runs `val Array(p1, p2, p3) = <field names>`. In the GraalVM
native image the case class is not registered for reflection, so `extractFieldNames`
returns an `Array[String]` of the wrong length and the destructure throws
`scala.MatchError: [Ljava.lang.String;`. This runs inside the companion object's
`<clinit>`, so it surfaces as `ExceptionInInitializerError` the first time a
`StartMessageMoveTask` request is handled.
**Proposed fix (preferred, one line):** use the explicit-field-name overload, which
does not reflect:
```scala
implicit val requestJsonFormat: RootJsonFormat[StartMessageMoveTaskActionRequest] =
jsonFormat(
StartMessageMoveTaskActionRequest.apply,
"SourceArn", "DestinationArn", "MaxNumberOfMessagesPerSecond"
)
Alternative fix: add StartMessageMoveTaskActionRequest (and any other case class
whose format is derived via reflective jsonFormatN) to the native-image
reflect-config.json / reachability metadata.
Secondary hardening: a failing/unsupported action request should not take the whole
broker down via pekko.jvm-exit-on-fatal-error; consider catching it in the route. But
the format derivation above is the root cause.
Note: the master source has this `jsonFormat3` line at ~56 and the case class at ~47-51; the `:74` in the trace is the line in the 1.7.1 build. Both point at the same
`StartMessageMoveTaskActionRequest` companion. I couldn't fetch the exact 1.7.1-tagged file (gh isn't authenticated here and the raw URL for that tag 404'd), so verify the precise line numbers
against the 1.7.1 tag before filing if you want them exact.
While I'm here, new UI is great, almost completely replaces some custom tooling I had written already (which stored recently sent messages in browser storage to be able to resend/template messages more quickly) - great job there!
Running the -native redrive, and while it appears to succeed, it crashes immediately afterwards with the following logs:
Claude is pretty certain this is a native graal vm problem - I've not worked with java in... 6(?) years now, so not much of an ability to dive straight into it anymore. I did have it produce this - hopefully it's useful to you. Apologies if the use of an LLM is inappropriate here - I didn't set it trying to find bugs, just as a diagnostic tool when I encountered this - here's its full output:
While I'm here, new UI is great, almost completely replaces some custom tooling I had written already (which stored recently sent messages in browser storage to be able to resend/template messages more quickly) - great job there!