I managed to track it down to the return value of one microflow. At a previous stage I'd had a return value for it, but removed the returned value, and set it to return Nothing (The microflow isn't currently called from anywhere but is work in progress.)
Changing it to return a value allowed the application to start up. Subsequently changing it back to return Nothing resolved the issue.
I think there's a possible bug in code generation in the modeller where after changing it, the return type or value of a microflow can get out of sync with the generated code. It appears this can cause runtime errors without showing modeller errors in some cases.
For anyone else who comes across this issue, try the above solution.
From the stacktrace it seems as if you have just a $ somewhere in your expression. I don't know why the modeler wouldn't give a consistency error about this.
To resolve it I would try and search the modeler for the text '$ ' (so the dollar sign followed by a white space). Hopefully you have an expression somewhere that says $ > 5 which is obviously invalid. If that doesn't work I would recommend searching on just the $ sign without the whitespace, this is obviously a lot of work, but I can't thing of many other ways to find the issue.
As an alternative you could try and start your application with TRACE logging enabled, this might print which microflow it was evaluating just before it gives you this exception.
Thanks Jasper, that's a great suggestion. I'd assumed that it would show as a consistency error if it were an issue in an expression I'd changed, but I can check that, as it's certainly possible I've made typos or failed to provide defaults properly whilst refactoring
So far, enabling TRACE debugging hangs with a spinner, and it doesn't show up with a search for "$ ". The search for "$" shows up 15000 results so that may not be feasible, but I can definitely check my recent changes.