Hi there,
is there a way to find all Assets which have failed Asset Renditions (so they have jcr:content/dam:failedRenditions where the reason is not "RenditionFormatUnsupported")?
We would need this information for the following two reasons:
- Check for corrupt Assets that can't be processed to manually resolve those issues
- Check if our custom processors (using the Asset Compute Microservice Extensibility) failed for some reason
Our initial approach was, to use a query for this, however this is very slow and fails for larger result sets.
For reference, here is the query we tried:
path=/content/dam/customer
type=dam:Asset
property=jcr:content/dam:failedRenditions/*/reason
property.operation=unequals
property.value=RenditionFormatUnsupported
p.limit=10
Are there any other good ideas on how one could solve this?
Thanks!
Anian
Solved! Go to Solution.
Views
Replies
Total Likes
Hi @webera,
The problem is you're using an XPath-like query to find assets where any dam:failedRenditions/*/reason != RenditionFormatUnsupported. This can be expensive because:
dam:failedRenditions is a child node with nested properties, which makes this a deep tree traversal.
The repository has to check each dam:Asset node under /content/dam/customer, drill into jcr:content/dam:failedRenditions, and then evaluate child properties.
Lucene indexing may not be optimized for this kind of nested query.
I would follow one of the option as below:
1. Use a Custom Sling Job / Groovy Script in AEM
Write a one-time or periodic script using Groovy (via ACS AEM Commons) or Java to traverse the repository efficiently in batches.
Groovy Script (via ACS AEM Commons):
import com.day.cq.dam.api.Asset
import javax.jcr.Node
def rootPath = "/content/dam/customer"
def assetManager = getService(com.day.cq.dam.api.AssetManager)
def resourceResolver = getResourceResolver()
def results = []
resourceResolver.getResource(rootPath).listChildren().each { res ->
def asset = res.adaptTo(Asset)
if (asset) {
Node failedNode = asset.adaptTo(Node).getNode("jcr:content/dam:failedRenditions")
if (failedNode && failedNode.hasNodes()) {
def iterator = failedNode.getNodes()
while (iterator.hasNext()) {
def rendition = iterator.nextNode()
def reason = rendition.getProperty("reason").getString()
if (!reason.equals("RenditionFormatUnsupported")) {
results.add(asset.getPath())
}
}
}
}
}
return results
You can tweak this to only check recent assets or those modified after a certain date.
2. Use an AEM Workflow Step (eg. Post-Processing Audit)
Create a workflow step that logs failed renditions to a custom metadata property (dam:processingStatus = failed-custom) whenever a custom processor fails.
Can be used to store failure reason as cq:lastCustomRenditionFailure
Use Oak Index optimization for fast retrieval
Then use a simple query on that metadata:
type=dam:Asset
path=/content/dam/customer
property=jcr:content/dam:processingStatus
property.value=failed-custom
3. Create a Custom Report Page in AEM
Use a Servlet or Coral UI-based tool to fetch/report assets failing rendition processing, querying in batches, paginating through the repository using QueryBuilder or JCR API.
Hi @webera,
The problem is you're using an XPath-like query to find assets where any dam:failedRenditions/*/reason != RenditionFormatUnsupported. This can be expensive because:
dam:failedRenditions is a child node with nested properties, which makes this a deep tree traversal.
The repository has to check each dam:Asset node under /content/dam/customer, drill into jcr:content/dam:failedRenditions, and then evaluate child properties.
Lucene indexing may not be optimized for this kind of nested query.
I would follow one of the option as below:
1. Use a Custom Sling Job / Groovy Script in AEM
Write a one-time or periodic script using Groovy (via ACS AEM Commons) or Java to traverse the repository efficiently in batches.
Groovy Script (via ACS AEM Commons):
import com.day.cq.dam.api.Asset
import javax.jcr.Node
def rootPath = "/content/dam/customer"
def assetManager = getService(com.day.cq.dam.api.AssetManager)
def resourceResolver = getResourceResolver()
def results = []
resourceResolver.getResource(rootPath).listChildren().each { res ->
def asset = res.adaptTo(Asset)
if (asset) {
Node failedNode = asset.adaptTo(Node).getNode("jcr:content/dam:failedRenditions")
if (failedNode && failedNode.hasNodes()) {
def iterator = failedNode.getNodes()
while (iterator.hasNext()) {
def rendition = iterator.nextNode()
def reason = rendition.getProperty("reason").getString()
if (!reason.equals("RenditionFormatUnsupported")) {
results.add(asset.getPath())
}
}
}
}
}
return results
You can tweak this to only check recent assets or those modified after a certain date.
2. Use an AEM Workflow Step (eg. Post-Processing Audit)
Create a workflow step that logs failed renditions to a custom metadata property (dam:processingStatus = failed-custom) whenever a custom processor fails.
Can be used to store failure reason as cq:lastCustomRenditionFailure
Use Oak Index optimization for fast retrieval
Then use a simple query on that metadata:
type=dam:Asset
path=/content/dam/customer
property=jcr:content/dam:processingStatus
property.value=failed-custom
3. Create a Custom Report Page in AEM
Use a Servlet or Coral UI-based tool to fetch/report assets failing rendition processing, querying in batches, paginating through the repository using QueryBuilder or JCR API.
Hi @SantoshSai ,
thank you very much for your detailed answer!
If I might, I would have to follow up questions:
Use Oak Index optimization for fast retrieval: I would need to extend the existing damAssetLucene index for that, right? How would the indexing of the child "dam:failedRenditions" look like? (Sorry, if this might be a beginner question, but we never extended the indexes, as we tried to avoid this up until now)
Thank you again and best regards,
Anian
1. Yes, the Groovy Console is part of ACS AEM Commons, not a standalone feature of AEM itself. When I mentioned "Groovy script via ACS AEM Commons", I meant running scripts using the Groovy Console provided by the ACS AEM Commons package.
2. Yes, to make querying on dam:failedRenditions performant, you would need to extend the existing damAssetLucene index (which is typically included by default in AEM).
"damAssetLucene": {
"jcr:primaryType": "oak:QueryIndexDefinition",
...
"indexRules": {
"dam:Asset": {
...
"properties": {
...
"failedReason": {
"name": "jcr:content/dam:failedRenditions/*/reason",
"propertyIndex": true,
"analyzed": true,
"type": "String"
}
}
}
}
}
Hi @webera ,
Instead of running heavy JCR queries, use an asynchronous background job or script that:
Iterates over assets under /content/dam/customer using ResourceResolver + AssetManager (Java or Groovy).
Checks if jcr:content/dam:failedRenditions exists.
Filters out entries where reason != "RenditionFormatUnsupported".
This avoids query size/time limits and works well at scale.
Alternative Options:
Use ACS Commons Report Builder with a custom datasource to scan for failed renditions.
If using AEMaaCS, consider using Adobe I/O Runtime or a Cloud Function for async scan.
Log/report such failures during asset upload via custom workflows or Asset Compute.
To monitor future failures, add a listener or process step in your custom workflow that logs/alerts on dam:failedRenditions.
Thanks!
Views
Likes
Replies