Skip to main content

Fixing Common Sling Model Injection Issues

Series: AEM Core Development — Part 5

Updated 5 min readMarkdown
Part of seriesAEM Core Development
Fixing Common Sling Model Injection Issues

Few things frustrate new AEM developers more than a component that renders blank, or a page that throws an error because a Sling Model failed to instantiate. The good news: most injection problems fall into a handful of patterns. This post walks through the usual suspects and how to diagnose each.

Symptom 1: The Model Is null in HTL

If ${hero.title} renders nothing and the whole model seems missing, Sling failed to adapt the request or resource to your class.

Common causes:

  • The bundle isn't active or the model isn't registered. Check /system/console/bundles and confirm your core bundle is in Active state. Then check /system/console/status-slingmodels to see whether your model class is listed.
  • Missing package export. Models must live in a package listed under Sling-Model-Packages or Sling-Model-Classes in the bundle manifest. The archetype configures this in the core module's pom.xml (via the bnd plugin), so if you add a new package, make sure it's covered.
  • Wrong adaptable. If your model declares adaptables = Resource.class but HTL is adapting from the request (the default for data-sly-use), or the reverse, adaptation fails. Match the adaptable to how the model is used.
  • Typo in the class name inside data-sly-use. HTL fails silently.

Symptom 2: Required Field Missing, Whole Model Fails

By default, injected fields are required. If one property doesn't exist on the resource, the entire model fails to instantiate, and you get null in HTL.

Fix options:

// Option A: make the whole model lenient
@Model(adaptables = Resource.class,
       defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)

// Option B: make a single field optional
@ValueMapValue
@Optional
private String subtitle;

// Option C: provide a default
@ValueMapValue
@Default(values = "Welcome")
private String title;

Because authors routinely leave fields empty or add new fields to dialogs later (leaving older content without the property), OPTIONAL is a safe default for most content models.

Symptom 3: Field Is Always null Even Though the Property Exists

The model instantiates, but a specific field is empty.

Check these:

  • Name mismatch. The field name (or the name attribute in @ValueMapValue(name = "...")) must match the JCR property exactly, and it's case-sensitive. A dialog saving ./heroTitle won't populate a field called title.
  • Wrong location. The property may live on a child node or on a different resource than the one the model is adapted from. Inspect the content in CRXDE Lite (/content/.../jcr:content/...) to see where the value actually is.
  • Wrong type. A property saved as a String being injected into a Boolean or Long field can fail or return null. Use {Boolean}true style types in dialogs where needed, and check how the value is stored.
  • Dialog was changed after content was authored. Existing content won't have new properties until authors re-save the component.

Symptom 4: @ScriptVariable or @SlingObject Doesn't Inject

  • @ScriptVariable only works when the model is adapted from a SlingHttpServletRequest, since script variables come from the request's scripting context. If your model adapts from Resource, use @SlingObject for the resolver or @Self plus other approaches instead.
  • @Self is useful to inject the adaptable itself, or to compose models.

Symptom 5: @OSGiService Is null

  • The service bundle may not be active, or the service may not be registered (check /system/console/components for the service component's state; it may be unsatisfied because of a missing configuration or dependency).
  • The interface used in the field must match what the service registers.
  • If the service is optional, mark the field with @Optional so the model doesn't fail.

Symptom 6: Multifield or Child Resource Lists Are Empty

  • Confirm the multifield dialog's name matches the child resource name (./links in the dialog means a child node named links).
  • Use @ChildResource for composite multifields, and make sure the generic type matches (List<Resource> or a child model class).
  • If using a child model class, it must also be a valid Sling Model adaptable from Resource.

A Debugging Checklist

When a model misbehaves, work through this in order:

  1. Is the bundle Active? (/system/console/bundles)
  2. Is the model registered? (/system/console/status-slingmodels)
  3. Check the logs. Sling Models log the reason for adaptation failures, often naming the field that couldn't be injected. Look at error.log for org.apache.sling.models messages.
  4. Inspect the actual content in CRXDE Lite to confirm property names, locations and types.
  5. Check the adaptable against how HTL (or other code) is invoking the model.
  6. Switch to OPTIONAL temporarily to isolate which field is causing failure.

Prevent Problems Early

  • Use injector-specific annotations (@ValueMapValue, @ChildResource, @OSGiService) instead of generic @Inject
  • Write unit tests with AEM Mocks, so injection issues surface at build time rather than on the page
  • Handle nulls in getters and @PostConstruct, since authors will always find a way to leave something blank

What's Next

So far we've worked with content stored directly on pages. The final post in this series moves to Content Fragment Models, the foundation for headless and structured content in AEM.


Next in this series: [Content Fragment Models for Headless]

About the author

  • AEM Technical Lead experienced with building and architecting solutions on AEM Sites and Assets. Sharing practical tutorials, real-world implementation lessons, and best practices to help fellow developers and leads navigate AEM.

What's the strangest Sling Model injection bug you've debugged? Share the symptom and the fix below. Real cases help everyone who searches for the same problem later.

AEM Core Development

Part 5 of 6

"Hands-on component building, Sling Models, HTL, and dialog configuration — the everyday toolkit every AEM developer needs."

Up nextContent Fragment Models for HeadlessSeries: AEM Core Development — Part 6