I'm looking again at the stack traces in the original report on StackOverflow - especially the second one, which has line numbers.
DocGen Result Exception. Response is invalid: Request is failed. Response body: {"message":"Error generating document (7cf581ac-2287-4396-bca4-0d5c5af9c308). Error: null (java.lang.NullPointerException)\n Stack Trace: java.lang.NullPointerException
at net.sf.saxon.functions.FunctionLibraryList.bind(FunctionLibraryList.java:124)
at net.sf.saxon.functions.FunctionLibraryList.bind(FunctionLibraryList.java:124)
at net.sf.saxon.expr.parser.XPathParser.parseFunctionCall(XPathParser.java:3356)
at net.sf.saxon.expr.parser.XPathParser.parseBasicStep(XPathParser.java:2206)
If we assume this is Saxon EE 9.9.1.8, then FunctionLibraryList#124 after EE pre-processing is line #126 in the original source, which is the recursive call
Expression func = lib.bind(functionName, staticArgs, env, reasons);
which is consistent with the fact that line #124 appears twice in the stack trace.
The only way this can throw an NPE is if lib
is null, which means that the FunctionLIbraryList
contains a null entry - specifically, the "inner" FunctionLibraryList, to account for two levels of recursive call.
The FunctionLibraryList was originally created by StylesheetPackage.createFunctionLibrary()
, locally to a compilation. This method constructs an inner FunctionLibraryList by calling Configuration.getBuiltInExtensionLibraryList()
. This method reads:
public FunctionLibraryList getBuiltInExtensionLibraryList() {
if (builtInExtensionLibraryList == null) {
builtInExtensionLibraryList = new FunctionLibraryList();
builtInExtensionLibraryList.addFunctionLibrary(VendorFunctionSetHE.getInstance());
builtInExtensionLibraryList.addFunctionLibrary(MathFunctionSet.getInstance());
builtInExtensionLibraryList.addFunctionLibrary(MapFunctionSet.getInstance());
builtInExtensionLibraryList.addFunctionLibrary(ArrayFunctionSet.getInstance());
builtInExtensionLibraryList.addFunctionLibrary(ExsltCommonFunctionSet.getInstance());
}
return builtInExtensionLibraryList;
}
The method is not synchronised, so two concurrent invocations could both find the initial condition builtInExtensionLibraryList == null
true, and could both then make concurrent modifications to the FunctionLibraryList, which could leave it in an inconsistent state.
So I think the fact that this method is not synchronised is consistent with the observed failure.