Konstantin,
On 4/20/26 3:08 PM, Konstantin Kolinko wrote:
пн, 20 апр. 2026 г. в 20:12, Christopher Schultz <[email protected]>:
All,
I just observed something in production that caused all kinds of weirdness.
java.lang.NullPointerException: Cannot invoke
"java.io.File.toURI()" because "base" is null
org.apache.jasper.JspCompilationContext.createOutputDir(JspCompilationContext.java:676)
at
org.apache.jasper.JspCompilationContext.getOutputDir(JspCompilationContext.java:196)
at
org.apache.jasper.JspCompilationContext.getClassFileName(JspCompilationContext.java:530)
at org.apache.jasper.compiler.Compiler.isOutDated(Compiler.java:441)
at org.apache.jasper.compiler.Compiler.isOutDated(Compiler.java:412)
at
org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:584)
at
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:379)
at
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:356)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:307)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
It looks like the value of javax.servlet.context.tempdir became null at
some point.
Hi, Chris!
Looking at the code (e.g. in Tomcat 11),
1) the "base" in org.apache.jasper.JspCompilationContext.createOutputDir
is "File base = options.getScratchDir();"
2) the "options" in org.apache.jasper.servlet.JspServlet.init() are
// Use the default Options implementation
options = new EmbeddedServletOptions(config, context);
(Those can be reconfigured to use a custom class, but it is unlikely
that you use that.)
I have nothing custom; I'm using a standard Tomcat out of the box. Only
standard changes to server.xml for <Connector>s.
3) org.apache.jasper.EmbeddedServletOptions constructor validates the value
and logs with "fatal" severity if the value is null or not an existing
directory:
if (scratchDir == null) {
log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir"));
return;
}
if (!(scratchDir.exists() && scratchDir.canRead() &&
scratchDir.canWrite() && scratchDir.isDirectory())) {
log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir",
scratchDir.getAbsolutePath()));
}
BTW, seeing a "return" above is odd, as this is in a constructor and
thus it skips processing of all other configuration options.
The scratchDir field in EmbeddedServletOptions is final, so there is
no way to change it afterwards, so you should have seen the log
message from EmbeddedServletOptions constructor.
4) Looking at o.a.c.core.StandardContext.postWorkDirectory()
if (!dir.mkdirs() && !dir.isDirectory()) {
log.warn(sm.getString("standardContext.workCreateFail",
dir, getName()));
}
...
context.setAttribute(ServletContext.TEMPDIR, dir);
context.setAttributeReadOnly(ServletContext.TEMPDIR);
The "dir" in a "dir.mkdirs()" call cannot be null, and the last line
prevents further changes to the value.
Thus my question about a stray "return" in point 3) becomes moot, as
it should not happen.
Yet you saw something.
Yup.
May it be that you are using some framework that mocks, wraps,
"instruments" the mentioned classes?
All is odd, given that the srratchDir field in EmbeddedServletOptions is final.
I'm not using JSPs much at all. I think one thing that may explain
what's happening specifically above is that we saw a file-upload
component failing due to a null temp dir, and only then did I launch a
JSP to inspect the servlet context. (We have a very small number of JSPs
deployed, so it's not entirely surprising that the JSP engine might not
be loaded at all until I tried this test, after knowing the temp dir was
null).
(A weirdness similar to an issue with JavaMelody, whatever that tool
is. E.g. oct 2025:
https://lists.apache.org/thread/v40g4opbcgs2s5ncdsl5qwg1l720oyfx
What is your version of Tomcat?
9.0.108
Any other oddities in the logs?
Nothing. I looked for a failure to discover the temp and/or work
directories, and I see nothing in catalina.out. (The log file goes back
months, and our most recent Tomcat restart was in March, while we do
reload the application periodically if we deploy a hot fix without
restarting the container).
The work directory is there, has the correct ownership, etc. and
contains files from both before and after the mishap.
Were there context starts/stops/restarts at the same time?
Not that we know of. Certainly not after we started investigating. This
was not a single error thrown a single time, either. Once the problem
was identified, it was trivially reproducible by loading any JSP.
Our fix was to restart the container and everything looks good, now.
So the root cause was that the temp dir servlet context attribute became
null, but I have no idea how that happened.
Unfortunately, I had to restart the container so I can't do any more
investigation at this point. :/
-chris
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]