I did a bit of testing and found that the culprit here is the Tomcat version. Stay away from Tomcat 9.0.116! This is the latest version on Homebrew, the latest Tomcat image on Docker Hub, etc. The issue isn't XNAT and it isn't the Docker image per se, it's something in 9.0.116. Basically any part of XNAT that uses Spawner (which is a JSON-based UI definition and rendering system inside XNAT) will fail to display. This is usually accompanied by an error in the browser console, so e.g. for
http://localhost:8080/setup (this is the setup page for an uninitialized XNAT running locally on top of Tomcat 9.0.116) I get:
There will also be messages in the error logs, e.g. turbine.log shows:
2026-03-25 14:45:21,365 [http-nio-8080-exec-8] ERROR org.apache.turbine.Turbine - Turbine.handleException:
java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:546)
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:187)
at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:108)
...
If you're running in docker-compose, the easiest fix is to modify the file xnat/Dockerfile from this:
FROM tomcat:9.0-jdk8-temurin-noble
To this:
FROM tomcat:9.0.115-jdk8-temurin-noble
If you have an existing xnat-web image, you'll want to delete that or force a build with docker-compose before restarting.
Note that the setup issue that Alex identified only affects new uninitialized installations, but the larger issue will cause other problems, like the Administer and Plugin Settings pages not displaying properly (well, at all!).