Hello Sitecorians! 👋
Welcome to another exciting blog!
Today, we are going to talk about something very practical that I have personally come across in my project experience, how to block a lifecycle transition in Sitecore Content Hub when required metadata is missing on an asset.
To explain this, I am creating a simple use case, you can follow the same approach and adapt it to your own business requirements.
So, let's get started! 😊
The Use Case
In this blog, our rule is simple:
An asset should not be allowed to change its lifecycle status if the Asset Type has not been set.
If the AssetTypeToAsset relation is empty at the time of the lifecycle transition, the system should block the change and show the user a clear error message:
"Cannot approve. Asset Type is missing."
This is just a demo use case to explain the approach. In your real project, you can check any field or relation — the pattern remains the same.
Understanding the Schema
From the API response, when an asset has an Asset Type set, it looks like this:
"AssetTypeToAsset": {
"parent": {
"properties": {
"Label": { "en-US": "Photo" }
},
"href": "https://epamdemo.sitecoresandbox.cloud/api/entities/46796"
},
"inherits_security": true
}
Notice "parent" is singular, not "parents". This means AssetTypeToAsset is a Child to One Parent relation (IChildToOneParentRelation), not a Child to Many Parents relation. This distinction is important in the script — using the wrong interface will throw a cast exception at runtime.
When Asset Type is not set, the relation has no parent at all. That is exactly the condition our script checks using relation.Parent == null.
Step 1: Create the Script
Go to Manage → Scripts and create a new script called ValidateAssetTypeOnApproval.
Paste the following code directly into the script editor:
using System;
using System.Linq;
using System.Threading.Tasks;
using Stylelabs.M.Framework.Essentials.LoadConfigurations;
using Stylelabs.M.Framework.Essentials.LoadOptions;
using Stylelabs.M.Scripting.Types.V1_0.Action;
using Stylelabs.M.Sdk;
using Stylelabs.M.Sdk.Contracts.Base;
using Stylelabs.M.Sdk.Exceptions;
var assetTypeRelation = "AssetTypeToAsset";
try
{
var asset = Context.Target as IEntity;
if (asset == null)
{
MClient.Logger.Info("ValidateAssetTypeOnApproval: Target entity is null. Exiting.");
return;
}
// Load the AssetTypeToAsset relation
await asset.LoadMembersAsync(
PropertyLoadOption.None,
new RelationLoadOption(assetTypeRelation)
);
var relation = asset.GetRelation<IChildToOneParentRelation>(assetTypeRelation);
// Block the lifecycle transition if Asset Type is not set
if (relation == null || relation.Parent == null)
{
MClient.Logger.Warn(
"ValidateAssetTypeOnApproval: AssetTypeToAsset is empty. Blocking lifecycle change.");
throw new ValidationException(
"Cannot approve. Asset Type is missing.",
new ValidationFailure(
"Cannot approve. Asset Type is missing.",
"ValidateAssetTypeOnApproval"));
}
MClient.Logger.Info(
$"ValidateAssetTypeOnApproval: AssetTypeToAsset present with id '{relation.Parent}'. Allowing.");
}
catch (ValidationException)
{
throw;
}
catch (Exception ex)
{
MClient.Logger.Error(
$"ValidateAssetTypeOnApproval: Unexpected error — {ex.Message}", ex);
}
Step 2: Create the Trigger
Go to Manage → Scripts → Triggers and create a new trigger called ValidateAssetTypeOnApproval.
General Tab
- Name:
ValidateAssetTypeOnApproval - Description:
Blocks the lifecycle transition if AssetTypeToAsset is not set on the asset. - Objective:
Entity modification - Execution type:
In process
Conditions Tab
Set up the following condition:
- Entity definition:
Asset (M.Asset) - Field:
FinalLifeCycleStatusToAsset - Value type:
current value - Operator:
contains→ selectApproved
This ensures the trigger only fires when the asset lifecycle is being changed to Approved not on every single save.
Actions Tab
Click Add action under Validation actions:
- Name:
ValidateAssetTypeOnApproval - Action type:
Action script - Script:
ValidateAssetTypeOnApproval
Click Save and then Save and close on the trigger.
Why Validation actions and not Pre-commit actions?
Validation actions are specifically designed to check a condition and block the operation if the check fails. Since we want to block the lifecycle transition not change any data Validation actions is the correct section to add our script.
It's Working! 🎉
Once the trigger and script are set up, when a user tries to change the lifecycle of an asset that has no Asset Type set, Content Hub immediately blocks the transition and shows this error in the UI:
Exactly what we wanted! The user gets a clear, actionable message telling them what is missing — and the lifecycle change is blocked until the Asset Type is set.
How It Works End to End
Scenario 1: Asset Type is missing
- User tries to change the lifecycle of an asset
- Trigger fires
FinalLifeCycleStatusToAssetcurrent value isApproved - Validation script runs and loads
AssetTypeToAsset relation.Parent == null— Asset Type not setValidationExceptionis thrown- Content Hub blocks the transition
- User sees: "Failed to change the life cycle. ValidateAssetTypeOnApproval: Cannot approve. Asset Type is missing."
Scenario 2: Asset Type is present
- User tries to change the lifecycle of an asset
- Trigger fires
FinalLifeCycleStatusToAssetcurrent value isApproved - Validation script runs and loads
AssetTypeToAsset relation.Parenthas a value — Asset Type is set- Script logs success and exits normally
- Lifecycle transition proceeds successfully
Conclusion
And that's a wrap! 🎉
This is a clean and simple pattern for enforcing metadata rules on lifecycle transitions in Sitecore Content Hub. The key things to remember:
- Add the script under Validation actions in the trigger this is what makes it a blocking validation
- Use
throw new ValidationException(msg, new ValidationFailure(msg, source))to block the transition and show the error to the user - Check the API response before choosing your relation.
- Set the trigger condition to fire only on the specific lifecycle status you want to guard
- You can extend this same script to validate multiple fields just add more checks before throwing
I hope this helps you in your Content Hub journey! If you have any questions, feel free to drop a comment below. 😊
Stay tuned for more! 👋