IllegalAccessException when starting a local Google App Engine instance

While developing a Java 17 app for Google App Engine, I ran into a strange exception when I ran this command to start my local development instance:

mvn clean package appengine:run

This was the stack trace:

[INFO] GCLOUD: java.lang.RuntimeException: Unable to create a DevAppServer
[INFO] GCLOUD:  at com.google.appengine.tools.development.DevAppServerFactory.doCreateDevAppServer(DevAppServerFactory.java:378)
[INFO] GCLOUD:  at com.google.appengine.tools.development.DevAppServerFactory.createDevAppServer(DevAppServerFactory.java:310)
[INFO] GCLOUD:  at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:384)
[INFO] GCLOUD:  at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:58)
[INFO] GCLOUD:  at com.google.appengine.tools.development.DevAppServerMain.run(DevAppServerMain.java:258)
[INFO] GCLOUD:  at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:249)
[INFO] GCLOUD: Caused by: java.lang.RuntimeException: java.lang.IllegalAccessException: class com.google.appengine.tools.development.StreamHandlerFactory cannot access a member of class java.net.URL (in module java.base) with modifiers "static"
[INFO] GCLOUD:  at com.google.appengine.tools.development.StreamHandlerFactory.invoke(StreamHandlerFactory.java:169)
[INFO] GCLOUD:  at com.google.appengine.tools.development.StreamHandlerFactory.getFallbackStreamHandler(StreamHandlerFactory.java:149)
[INFO] GCLOUD:  at com.google.appengine.tools.development.StreamHandlerFactory.<init>(StreamHandlerFactory.java:127)
[INFO] GCLOUD:  at com.google.appengine.tools.development.StreamHandlerFactory.install(StreamHandlerFactory.java:87)
[INFO] GCLOUD:  at com.google.appengine.tools.development.DevAppServerImpl.<init>(DevAppServerImpl.java:135)
[INFO] GCLOUD:  at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
[INFO] GCLOUD:  at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
[INFO] GCLOUD:  at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
[INFO] GCLOUD:  at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
[INFO] GCLOUD:  at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
[INFO] GCLOUD:  at com.google.appengine.tools.development.DevAppServerFactory.doCreateDevAppServer(DevAppServerFactory.java:363)
[INFO] GCLOUD:  ... 5 more
[INFO] GCLOUD: Caused by: java.lang.IllegalAccessException: class com.google.appengine.tools.development.StreamHandlerFactory cannot access a member of class java.net.URL (in module java.base) with modifiers "static"
[INFO] GCLOUD:  at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:392)
[INFO] GCLOUD:  at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:674)
[INFO] GCLOUD:  at java.base/java.lang.reflect.Method.invoke(Method.java:560)
[INFO] GCLOUD:  at com.google.appengine.tools.development.StreamHandlerFactory.invoke(StreamHandlerFactory.java:167)
[INFO] GCLOUD:  ... 15 more
Screenshot of IllegalAccessException stack trace

While this stacktrace appeared unhelpful initially, it actually provided a clue as to where the problem could be. An IllegalAccessException was thrown by the JDK when it was performing a reflection operation for App Engine’s development tools.

The engineers at Google who wrote the App Engine development tools must’ve had them working on their local machine.

What could be the difference between theirs and mine?

I was using the relatively new JDK 17, whereas a lot of App Engine’s documentation was for JDK 11. I figured maybe I was using a JDK that was too new.

So I downgraded Maven’s JDK to version 11, and sure enough the problem went away.

<properties>
  <maven.compiler.target>11</maven.compiler.target>
  <maven.compiler.source>11</maven.compiler.source>
</properties>

Do you practice Basecamp’s Shape Up methodology at work? Check out our Shape Up Board for Jira plugin.

Previous
Previous

Is Shape Up just a nice theory?

Next
Next

Deploying a Django app to AWS using Elastic Beanstalk