fix(content-api): guard against null ContentType in StoryBlock refresh path (#33645)#36378
fix(content-api): guard against null ContentType in StoryBlock refresh path (#33645)#36378gortiz-dotcms wants to merge 2 commits into
Conversation
…h path (#33645) `Contentlet.getContentType()` performs a DB/cache lookup on every call and can return null when the content-type cache is transiently invalidated (e.g. during a push-publish bundle import). Three call sites called the method twice with no atomicity guarantee — the first call was used as a null guard, but the second call (inside the body) could return null, producing a NullPointerException. Because `ContentUtils.pull()` wraps `conAPI.search()` with a `catch (Throwable)` that swallows all exceptions and returns an empty list, the NPE was silent and the API returned `{"contentlets":[]}` with only a WARN log. Fix: call `getContentType()` once per code path, store the result in a local variable, and guard against null before accessing any method on the result. Affected call sites: - `ESContentFactoryImpl.processCachedContentlet()` — two calls collapsed to one - `StoryBlockAPIImpl.refreshReferences()` — three calls collapsed to one - `PushPublishigDependencyProcesor.processStoryBockDependencies()` — added null guard before `hasStoryBlockFields()` (was unconditional, most likely to NPE during push-publish because the cache invalidation happens on that same thread) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🤖 dotBot Review (Bedrock)Reviewed 3 file(s); 1 candidate(s) → 0 confirmed, 0 uncertain (unverified, kept for review). ✅ No issues found after verification. us.deepseek.r1-v1:0 · Run: #28516485849 · tokens: in: 10527 · out: 3734 · total: 14261 · calls: 4 · est. ~$0.034 |
|
Claude finished @gortiz-dotcms's task in 2m 5s —— View job 🔍 dotCMS Backend Review
All four review dimensions (Security, Database, Java Standards, REST API) returned no findings. The fix correctly collapses multiple |
|
✅ dotCMS Backend Review: no issues found. |
|
Tick the box to add this pull request to the merge queue (same as
|
Summary
Contentlet.getContentType()performs a DB/cache lookup on every call and can returnnullwhen the content-type cache is transiently invalidated — most commonly during a push-publish bundle import, which callsContentTypeCache2Impl.remove()for each updated type.Three call sites used the method in a TOCTOU pattern: the first call served as a null guard, but the second call (inside the branch body) could race against the cache invalidation and return
null, producing an NPE. BecauseContentUtils.pull()wrapsconAPI.search()with acatch (Throwable)that swallows all exceptions and returns an empty list, the NPE was silent — the content API returned{"contentlets":[]}with only aWARN util.ContentUtils - nulllog entry.Changes
Call
getContentType()once per code path, store the result in a local variable, and null-guard before accessing any method on it.ESContentFactoryImpl.processCachedContentlet()StoryBlockAPIImpl.refreshReferences()PushPublishigDependencyProcesor.processStoryBockDependencies()hasStoryBlockFields()— was unconditional; most likely to NPE during push-publish since cache invalidation happens on that same threadRegression Analysis
StoryBlockAPITestintegration tests remain valid; the fix only closes the null-dereference gapCloses #33645
Test plan