Skip to content

fix(content-api): guard against null ContentType in StoryBlock refresh path (#33645)#36378

Queued
gortiz-dotcms wants to merge 2 commits into
mainfrom
issue-33645-npe-content-type-null
Queued

fix(content-api): guard against null ContentType in StoryBlock refresh path (#33645)#36378
gortiz-dotcms wants to merge 2 commits into
mainfrom
issue-33645-npe-content-type-null

Conversation

@gortiz-dotcms

Copy link
Copy Markdown
Member

Summary

Contentlet.getContentType() performs a DB/cache lookup on every call and can return null when the content-type cache is transiently invalidated — most commonly during a push-publish bundle import, which calls ContentTypeCache2Impl.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. Because ContentUtils.pull() wraps conAPI.search() with a catch (Throwable) that swallows all exceptions and returns an empty list, the NPE was silent — the content API returned {"contentlets":[]} with only a WARN util.ContentUtils - null log entry.

Changes

Call getContentType() once per code path, store the result in a local variable, and null-guard before accessing any method on it.

File Change
ESContentFactoryImpl.processCachedContentlet() Two calls collapsed to one cached local variable
StoryBlockAPIImpl.refreshReferences() Three calls collapsed to one cached local variable
PushPublishigDependencyProcesor.processStoryBockDependencies() Added null guard before hasStoryBlockFields() — was unconditional; most likely to NPE during push-publish since cache invalidation happens on that same thread

Regression Analysis

  • No behavioral change for contentlets with a resolvable content type — the same checks pass as before
  • Contentlets whose content type is null (deleted or orphaned) are now safely skipped instead of throwing NPE
  • All existing StoryBlockAPITest integration tests remain valid; the fix only closes the null-dereference gap

Closes #33645

Test plan

  • Verify the content API returns results (not an empty array) under concurrent push-publish activity
  • Confirm no regressions in StoryBlock field rendering for normal content
  • Check that push-publish dependency analysis completes without NPE when processing StoryBlock contentlets

…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>
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

🤖 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

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @gortiz-dotcms's task in 2m 5s —— View job


🔍 dotCMS Backend Review

  • Load dotCMS conventions
  • Get the Java diff
  • Run specialized sub-agent reviews (Security, Database, Java Standards, REST API)
  • Consolidate findings and post review

All four review dimensions (Security, Database, Java Standards, REST API) returned no findings. The fix correctly collapses multiple getContentType() calls into a single cached local variable and adds the missing null guard in PushPublishigDependencyProcesor — no behavioral changes for valid contentlets, no new issues introduced.

@claude

claude Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

dotCMS Backend Review: no issues found.

@mergify

mergify Bot commented Jul 1, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@dsilvam dsilvam added this pull request to the merge queue Jul 1, 2026
Any commits made after this event will not be merged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Safe To Rollback Area : Backend PR changes Java/Maven backend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[DEFECT] NPE when fetching content via content api with depth 3 and high limit

2 participants