Workflow Loop Issue

I have created a test workflow to print loop input. So, that i can use later.

Can anyone suggest me what is wrong with loop input?

Please find workflow json attached too.

{
	"name": "Iterate Identities and Send Email",
	"description": "Workflow to iterate through identities using a loop and send an email for each identity",
	"modified": "2026-07-08T12:06:14.354944323Z",
	"modifiedBy": {
		"type": "IDENTITY",
		"id": "a244f1b207a44c858c838ccbf56a2332",
		"name": "6099714"
	},
	"definition": {
		"start": "Get List of Identities",
		"steps": {
			"End Step - Success": {
				"actionId": "sp:operator-success",
				"displayName": "End Step - Success",
				"type": "success"
			},
			"Get List of Identities": {
				"actionId": "sp:get-identities",
				"attributes": {
					"inputQuery": "6099123456",
					"searchBy": "searchQuery"
				},
				"displayName": "Get List of Identities",
				"nextStep": "Loop Through Identities",
				"type": "action",
				"versionNumber": 2
			},
			"Loop Through Identities": {
				"actionId": "sp:loop:iterator",
				"attributes": {
					"input.$": "$.getListOfIdentities.identities",
					"loopInput.$": "$.getListOfIdentities",
					"start": "Send Email to Identity",
					"steps": {
						"End Loop Step": {
							"actionId": "sp:operator-success",
							"displayName": "End Loop Step",
							"type": "success"
						},
						"Send Email to Identity": {
							"actionId": "sp:send-email",
							"attributes": {
								"body": "<p>Hello ${{loop.loopInput.displayName}}, this is an automated email notification.</p>\n<p>{{$.loopThroughIdentities.loopInput}}</p>\n<p>{{loop.loopInput}}</p>",
								"context": {
									"displayName.$": "$.loop.loopInput.displayName"
								},
								"from": "no-reply@sailpoint.com",
								"recipientEmailList": [
									"amrit.raj@lseg.com"
								],
								"replyTo": null,
								"subject": "Notification for Identity"
							},
							"displayName": "Send Email to Identity",
							"nextStep": "End Loop Step",
							"type": "action",
							"versionNumber": 2
						}
					}
				},
				"displayName": "Loop Through Identities",
				"nextStep": "End Step - Success",
				"type": "action",
				"versionNumber": 1
			}
		}
	},
	"creator": {
		"type": "IDENTITY",
		"id": "a244f1b207a44c858c838ccbf56a2332",
		"name": "6099123456"
	},
	"trigger": {
		"type": "EXTERNAL",
		"attributes": {
			"id": "idn:external-http",
			"integrationId": null
		}
	}
}

This is what i have received as email.

Hello ${{loop.loopInput.displayName}}, this is an automated email notification.

{{$.loopThroughIdentities.loopInput}}

{{loop.loopInput}}

${{loop.loopInput.displayName}} it should be {{$.loop.loopInput.displayName}}

Hello Amrit, you have a couple of small syntax issues in the email body that are causing the expressions to print as raw text instead of resolving.

1. The email body syntax: Your Send Email step already has the context mapping set up correctly:

"context": {
  "displayName.$": "$.loop.loopInput.displayName"
}

So in the email body, just reference it as ${displayName}:

<p>Hello ${displayName}, this is an automated email notification.</p>

Right now your body has ${{loop.loopInput.displayName}} which mixes two different syntax styles, that’s why it prints raw instead of resolving. The Send Email action uses its Templating Context to resolve variables, so map what you need in the context and then use ${variableName} in the body. That’s the documented approach.

2. Step reference inside the loop: This part also won’t resolve:

{{$.loopThroughIdentities.loopInput}}

Inside a loop, the current item is always accessed through $.loop.loopInput, not through the step name. So for your Send Email context mappings, use $.loop.loopInput.displayName, $.loop.loopInput.name, $.loop.loopInput.id, etc.

3. The loopInput.$ in your loop config: I would remove this line from your loop attributes:

"loopInput.$": "$.getListOfIdentities"

Your loop input array is already defined here:

"input.$": "$.getListOfIdentities.identities"

That’s the array the loop iterates through, and each identity from it automatically becomes available as $.loop.loopInput. The extra loopInput.$ line is not needed and can make the config confusing. Official reference.

Thanks, @punna0001 I have fixed that.
I have printed loop input in email and output is like below

Then I have checked step output of loop where I can see loopinput as _index, _type and type. Then how will I get identity name or id or other identity attribute?

"loop":{
"context": null ,
"loopInput":{
"_index": "61" ,
"_type": "identity" ,
"type": "identity"
}
}

Your loop input is only carrying reference metadata right now. So there is no displayName, name, email, or id available at that point. First, open the output of Get List of Identities and check what’s actually inside $.getListOfIdentities.identities. For the loop to use identity fields directly, each item in that array must contain those fields, especially id.

If id is available, add a Get Identity step inside the loop before Send Email and pass the current identity id: $.loop.loopInput.id .Your loop should be:

Get List of Identities
→ Loop Through Identities
   → Get Identity (input: $.loop.loopInput.id)
   → Send Email
   → End Loop Step

Then in the Send Email context, pull values from the Get Identity output:

{
  "displayName.$": "$.getIdentity.name",
  "identityId.$": "$.getIdentity.id",
  "email.$": "$.getIdentity.emailAddress"
}

And in the body:

<p>Hello ${displayName},</p>
<p>Identity ID: ${identityId}</p>
<p>Email: ${email}</p>

Also keep the loop input simple: "input.$": "$.getListOfIdentities.identities"

Remove the extra loopInput.$ line if it’s still there.

The main thing is $.loop.loopInput only contains whatever item the loop is iterating over. If that item only has _index, _type, and type, there’s no identity data to use in the email. Get the identity id into the loop first, then use Get Identity to fetch the full details.

tried but it fails

You have got the Get Identity input set correctly to $.loop.loopInput.id, so that part is good. The reason it might still be failing is because the loop item doesn’t actually contain an id field. We already saw it only has _index, _type, and type.

The fix is upstream in your Get List of Identities step. Open its Step Output and check what fields each identity item actually contains. If id is missing, add it in the Additional Output Data section of that step’s configuration.

Once id is included in the Get List output, the loop items will carry it, and $.loop.loopInput.id will resolve properly into Get Identity.

Can you share the Step Output of Get List of Identities so we can see exactly what’s coming back?