matrei commented on PR #16467:
URL: https://github.com/apache/grails-core/pull/16467#issuecomment-5956534523

   @jdaugherty Thanks, that context helps.
   
   **#1:** I don't think 7.x is protected here any more than 8.x is. The 
wrapping you mention is the same on both lines. Spring 6.2's and 7.0's 
`DispatcherServlet.doDispatch` wrap a non-`Exception` `Throwable` the same way: 
I diffed 6.2.19 against 7.0.9, and only the last-modified handling moved. In 
both versions, the wrapped exception reaches `afterCompletion` as `ex`, and the 
attribute is never read. The crash happens when `ex` is null and the 
`exception` attribute holds something that isn't an `Exception`. Everything 
that can put such a value there exists on 7.x too: a model entry, or an error 
handler that copies the container's `jakarta.servlet.error.exception` (see #2). 
The `(Exception)` cast is identical on `7.0.x` 
(`GrailsInterceptorHandlerInterceptorAdapter.groovy:122`).
   
   So I think the Spring Session bug produced the `Error`, and the upgrade is 
just where it surfaced. A 7.x app with the same failing filter, or with `model: 
[exception: 'Something went wrong']`, crashes the same way. The fix is small, 
has no API impact, and the tests are self-contained. Could you retarget it to 
`7.0.x` and let it merge up?
   
   **#2:** I believe you hit a real `Error` there. I think it reached the 
attribute by a different route than the guide describes, though, and I'd like 
the guide to describe the route you actually saw. Here is what I could and 
couldn't find on `8.0.x`:
   
   - `GrailsExceptionResolver.setStatus` is the only framework code that writes 
`exception`, and it always writes a `GrailsWrappedRuntimeException`.
   - Inside the dispatch, an `Error` is still wrapped in a `ServletException` 
(Spring 7.0.9 `doDispatch`). When the resolver doesn't handle it, 
`afterCompletion` receives it as `ex`, and the attribute is never read.
   - An `Error` thrown outside the `DispatcherServlet` goes to the container. A 
Spring Session commit is one example, because `SessionRepositoryFilter` commits 
after the servlet returns. The container stores the bare `Error` in 
`jakarta.servlet.error.exception`, not in `exception`, and then makes an ERROR 
dispatch. `grailsInterceptorMappedInterceptor` is a `MappedInterceptor` and 
nothing excludes ERROR dispatches, so the interceptors run again for the error 
handler. That fits what you saw. But something in that error handler still has 
to copy the `Error` into `exception`, for example a status-code controller that 
renders `model: [exception: 
request.getAttribute('jakarta.servlet.error.exception')]`.
   
   Do you still have the stack trace, or can you tell what handled the 500 in 
that app? If it is the ERROR dispatch path, I'd suggest:
   
   - Guide: say that `throwable` may be any `Throwable`, including an `Error` 
that reaches the container's error page from outside the action (for example 
from a servlet filter). Also say that an `Error` thrown by an action arrives 
wrapped, so you reach it through `getCause()`.
   - Tests: one feature that follows that path, so the test shows the scenario 
that actually happened.
   
   Either way, the fix itself is correct. The suggestions in #2 are only about 
making the docs match what users will see. The branch question in #1 is the 
only thing I would like settled before it merges.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to