AEM Sites Developer Expert study materials
AEM Sites Developer Expert study resources

Sling Model Injection Returns Null Only on Publish

AEM Sites Developer Expert · Put your knowledge to work in context.

All case studies

Sling Model Injection Returns Null Only on Publish

A product-card component uses a Sling Model with @Inject @Via("resource") for a productSku field and @ChildResource for a nested price node. On author it renders correctly. On publish, productSku is null for roughly 30% of pages, while price always resolves. The productSku value is set in the component dialog and is also available from a product-data service. The model is registered with @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL). Pages were activated via a tree activation, and some were later edited and activated individually. The publish tier runs the same code package. There is no dispatcher in front of the author tier.

1. Explain why `productSku` is intermittently null on publish while `price` is not, and what the injection strategy contributes.

Read the worked answer

Two facts interact: OPTIONAL injection strategy means a missing property does not fail the model-it silently leaves the field null. So the model never throws; it renders an empty card. @ChildResource for price resolves a child node that exists on the resource regardless of the property, so it is stable. productSku is a property injection from the resource; if the property is absent on the publish instance's node, the field is null.

The intermittency (30%) matches partial replication: tree activation replicated the pages at one point, then individual edits were activated. If an author set productSku on a page but the activation of that specific page was skipped or failed (or was activated before the edit), publish's node lacks the property while author has it. price as a child node was likely created earlier and replicated with the tree activation, so it survives. The OPTIONAL strategy means there is no error to surface the gap.

The fix is process plus guard: reconcile publish content (re-activate affected pages or run a content package diff), and change the model to fall back to the product-data service when the injected value is null, rather than relying on OPTIONAL to hide missing data. Consider REQUIRED for fields that must exist so failures are loud in logs.

2. What would you change in the model to make this class of failure visible during QA?

Read the worked answer

Keep OPTIONAL for genuinely optional fields, but for business-critical ones add explicit validation rather than silent nulls:

  • Inject the value, then in an @PostConstruct method check for null and log a WARN with resource.getPath() so QA logs reveal gaps.
  • For fields that must exist, switch to DefaultInjectionStrategy.REQUIRED on that field (or @Required where applicable) so a missing property throws and the component fails visibly instead of rendering an empty card.
  • Add a fallback resolver that queries the product-data service when the resource property is null, and log when the fallback is used-this both fixes rendering and creates a signal that content is out of sync.
  • Add a lightweight content health check (a servlet or scheduled job) that scans product-card instances for missing productSku and reports counts, so partial replication is caught before QA.

This converts an invisible content-sync problem into an observable one without masking it.