Fix NPE/RTimer assertion when a V2 request fails before a SolrQueryRequest is attached - #4674
Fix NPE/RTimer assertion when a V2 request fails before a SolrQueryRequest is attached#4674epugh wants to merge 2 commits into
Conversation
…Jersey request fails before a SolrQueryRequest is attached to the request context. Discovered while investigating an intermittent CollectionsApi.GetCollectionStatus failure under basic-auth-secured clusters. When a request fails early (before V2HttpCall attaches a SolrQueryRequest to the Jersey request context), CatchAllExceptionMapper.processAndRespondToException passed a null req into RequestHandlerBase.processReceivedException, which unconditionally called req.getCore(), throwing an NPE while already handling an exception. Jersey then re-invoked the response filter chain via its "already mapped exception" path, causing RequestMetricHandling.PostRequestMetricsFilter to call stop() a second time on an already-stopped timer, triggering RTimer's assertion (visible only with assertions enabled, e.g. in test runs). Fixes: - RequestHandlerBase.processReceivedException: null-check req before req.getCore(). - CatchAllExceptionMapper.buildExceptionResponse: null-check solrQueryRequest before solrQueryRequest.getParams(). - PostRequestDecorationFilter / PostRequestLoggingFilter: null-check solrQueryRequest before dereferencing it. - RequestMetricHandling.PostRequestMetricsFilter: guard against being invoked more than once for the same request (clears the TIMER property after stopping it). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
I am still trying to "prove" that this is an issue on main.... |
|
Hey @epugh, are you sure you referenced the right issue? Wondering because I'm the author of SOLR-18322 and I don't see how that's relevant for it 🙂 |
So, I just yelled at my damn Claude... who went rogue and opend up this PR while I was just chatting... Sigh. Thank you. So then I was going to just go and open a JIRA and get that number! THanks. |
i actually was shocked that it just "did it", I know, I shouldn't have been. |
…number. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
This PR was accidentally closed when its branch got renamed outside of GitHub's branch-rename API (which would have carried the PR along automatically) — the branch was deleted instead, which auto-closes any PR pointing at it. Reopened with the same content, corrected to reference the actual JIRA ticket number, as #4676. |
Summary
Discovered while investigating an intermittent
CollectionsApi.GetCollectionStatusfailure under basic-auth-secured clusters (used while migratingbin/solr deleteoff ZooKeeper). The endpoint would fail intermittently with:...cascading into Jersey re-invoking the response filter chain via its "already mapped exception" fallback path, which in turn caused
RequestMetricHandling.PostRequestMetricsFilterto call.stop()a second time on an already-stopped timer — trippingRTimer'sassert state == STARTED || state == PAUSED(only visible with assertions enabled, e.g. under-eatest runs; silently harmless in production builds where the assert is compiled out).Root cause: when a request fails before
V2HttpCallattaches aSolrQueryRequestto the Jersey request context (the actual trigger appears to be a rare race in inter-node request handling — not fully root-caused, but independent of any specific endpoint), several Jersey filters/mappers inorg.apache.solr.jerseyunconditionally dereference that possibly-nullSolrQueryRequest, causing a second, cascading exception while trying to handle the first one.Changes
RequestHandlerBase.processReceivedException: null-checkreqbefore callingreq.getCore().CatchAllExceptionMapper.buildExceptionResponse: null-checksolrQueryRequestbefore calling.getParams().PostRequestDecorationFilter/PostRequestLoggingFilter: null-checksolrQueryRequestbefore dereferencing (mirrors the existing, correct null-check already present inMediaTypeOverridingFilter, which had a// TODO Is it valid for SQRequest to be null?comment confirming this was already a known possibility).RequestMetricHandling.PostRequestMetricsFilter: guards against being invoked more than once for the same request by clearing theTIMERproperty after stopping it, so a second (re-entrant) invocation is a no-op instead of crashing.Test plan
RequestHandlerBaseTest(nullreqcases),PostRequestLoggingFilterTest,PostRequestDecorationFilterTest(new),RequestMetricHandlingTest(new) — each verified to fail without the corresponding fix and pass with it (confirmedRequestMetricHandlingTest.testPostRequestMetricsFilterToleratesBeingInvokedTwicefails ongit stashof just theRequestMetricHandling.javafix, passes once restored)CatchAllExceptionMapperTest(SOLR-18066) still passes — no regression tohideStackTracehandlingGetCollectionStatusunder aSecurityJson.SIMPLE-secured 2-node cluster (~40% failure rate over multiple runs); with these fixes applied, 15/15 consecutive runs passed./gradlew :solr:core:spotlessJavaCheckclean./gradlew :solr:core:compileJava :solr:core:compileTestJavaclean🤖 Generated with Claude Code