Some time back, we found a bug in our workflows where the call:refreshIdentity wasn’t being called because of a faulty initialized conditional. Now that it is working, we are getting consistent errors when we do the call:refreshIdentity function. I know that this is akin to the Lazy Initialization Exception problem that occurs with Hibernate, but this case is inside a Workflow. I know how to fix it in a Rule, but not here.
What I am not sure about is why we are getting this type of Application error: An unexpected error occurred: could not initialize proxy [sailpoint.object.Application#0ad200e18a191ba5818a19fbeb780018] - no Session
That application ID is the Active Directory application for us.
My hunch is that doing a commitTransaction and not doing something with the identity or context is what is messing us up. However, I am not sure where to start. Help is much appreciated.
Hi @acrumley
Alternatively, you can create an IIQ plan (see example, below) and use it for provisioning instead of directly setting the identity attribute. This approach is recommended as the best practice. To initiate provisioning, you can either invoke the out-of-the-box (OOTB) LCM Provisioning workflow or utilize a provisioner.
ProvisioningPlan plan = new ProvisioningPlan();
Identity identity = context.getObjectByName(Identity.class, identityName);
plan.setIdentity(identity);
AccountRequest accountReq = new AccountRequest(AccountRequest.Operation.Modify,"IIQ",null,identityName);
accountReq.add(new AttributeRequest("inactive", Operation.Set, true));
plan.add(accountReq);
Moderator Note Dec 2025
Please note that the response below is from AI and contains known errors. It is not being deleted as it was marked as a solution but proceed with caution and double check for accuracy.
Why the LazyInitializationException shows up in this workflow
context.commitTransaction() closes the Hibernate session for this step.
When the step ends, the workflow engine expects the session that it opened at the beginning of the step to still be alive so it can flush and commit after the step finishes. Calling commitTransaction() yourself closes that session early and detaches every object that was loaded in it ( Identity, its Links, the Application proxies inside each link, etc.).
call:refreshIdentity immediately runs in the very next step. refreshIdentity reloads the identity, then walks through the links (link.getApplication()), roles, entitlements, … If any of those objects are still the detached proxies that were created in the previous (now‑closed) session, Hibernate tries to initialise them and throws
org.hibernate.LazyInitializationException:
could not initialize proxy – no Session
This is exactly the pattern described in SailPoint’s developer thread on this error - org.hibernate.LazyInitializationException.
3. The proxy you see in the stack trace belongs to your AD application (Id 0ad200e18a19…), so the first lazy fetch that fails is link.getApplication().
The fix: let the workflow engine do the commit for you
<Step icon="Task" name="Set Identity Attribute">
<Arg name="identityName" value="ref:identityName"/>
<Script>
<Source><![CDATA[
import sailpoint.object.Identity;
Identity identity =
context.getObjectByName(Identity.class, identityName);
// clear the attributes – use nulls if you really want them removed
identity.setAttribute("iiqleaverdate", null);
identity.setAttribute("termDate", null);
identity.setAttribute("new_uname", null);
identity.setAttribute("comments", null);
context.saveObject(identity); // **no commitTransaction()**
// If you want to be 100 % sure the row is written before
// the next step starts you can add
// sailpoint.tools.Util.flushContext(context);
]]></Source>
</Script>
<Transition to="Refresh Identity"/>
</Step>
Because you did not close the session, all proxies belong to a live session and refreshIdentity can traverse them safely.
Tip: If, for some reason, you absolutely must commit in the middle of the step, call
context.commitTransaction();
context.startTransaction(); // reopen a fresh session
and *do not* keep references to objects loaded in the old session. Reload them instead.
Best‑practice reminders
Topic
Recommendation
Attribute clearing
Use null (or identity.removeAttribute()) rather than empty string if you really want the attribute to disappear.
Locking
When a workflow writes an Identity, use ObjectUtil.lockIdentity() if concurrent updates are possible.
Performance
Excessive manual commitTransaction() calls can hurt overall throughput. Avoid them inside loops or high‑volume workflows.
Debugging
If you still see lazy‑load errors, add log4j.logger.org.hibernate=debug to capture the exact field that fails, or reload the object in the current session (context.getObjectById(...)).
After removing the premature commit most teams find the refresh step runs without the “no Session” error. Let me know if you still see stack traces – we can look at log excerpts and tune the refresh arguments next.
This is an awesome reply! I will be sharing these best practices with my team. I believe your post contains the solution, but I do want to be sure that I am communicating properly. We are not getting the specific LazyInitializationException error. However, we are getting errors like this:
So I think your comment on the session being open or closed is the most pertinent. In our workflow, we actually use two different patterns,
For some, we use the access request and do a provisioning plan (because we want to see an M365 license get provisioned). However, we don’t want to see this backend identity attribute stuff show up in the Access Requests.
In places upstream in the workflow, we use a pattern like this:
// Lock identity and set IIQJoinerDate to processing so another joiner is not ran
ObjectUtil.lockIdentity(context, identity);
identity.setAttribute("iiqjoinerdate", "PROCESSING");
ObjectUtil.unlockIdentity(context, identity);
// Save object and commit transaction
context.saveObject(identity);
context.commitTransaction();
And based on your best practices, it should be this:
// Lock identity and set IIQJoinerDate to processing so another joiner is not ran
ObjectUtil.lockIdentity(context, identity);
identity.setAttribute("iiqjoinerdate", "PROCESSING");
ObjectUtil.unlockIdentity(context, identity);
context.saveObject(identity);
...
// Let the refresh step do the committransaction()