Transform VTL behavior

I have found that if the value of a dynamic variable that is consumed in an VTL expression is set to an empty string, you can’t even use it in the VTL to test, e.g., "#if($bar)$bar#end", it throws.

The solution is to wrap whatever is being assigned with a first-valid and return something:

{
  "name": "foo",
  "type": "static",
  "attributes": {
      "bar": {
          "type": "firstValid",
          "attributes": {
              "values": [
                  {
                      "attributes": {
                          "id": "Get Something"
                      },
                      "type": "reference"
                  },
                  "none"
              ]
          }
      },
      "value": "#if($bar != 'none')$bar#end"
  }
}

Why is that entire layer of indirection necessary? Does the SailPoint code simply not even inject the variable in the VTL environment if the value is empty?

Is there a way to avoid all of this overhead?

Hi @josephcasale ,

Based on your ‘if’ condition, there is no need to use first valid transform to catch null value.

“value”: “#if($bar)$bar#end” - this condition check if $bar has value, if yes then the output is same if not there is no output. Check this for more info Apache Velocity Engine - User Guide

{
  "name": "foo",
  "type": "static",
  "attributes": {
      "bar": {
          "attributes": {
              "id": "Get Something"
               },
               "type": "reference"
          }
      },
      "value": "#if($bar)$bar#end"
}

@josephcasale -

The Basic Problem

When SailPoint IdentityNow sees that a dynamic attribute’s value is an empty string (""), it doesn’t pass that value into the Apache Velocity environment at all. So if your VTL (Velocity Template Language) tries to do something like:

#if($bar)
  The value of bar is: $bar
#end

…and $bar happens to be an empty string, $bar doesn’t exist at all in Velocity. That often results in an error (or unexpected behavior) because Velocity thinks $bar was never defined.


Why “Wrapping” with a Fallback Solves It

To make sure $bar is always defined in Velocity, you give it a fallback value when it’s empty (for example "none"). That way, $bar will never be truly empty—it will at least be "none". Then you can say in your Velocity code:

#if($bar != "none")
  The value of bar is: $bar
#end

This check makes sure you only show (or use) $bar if it’s not "none". By doing this, you avoid the entire “variable doesn’t exist” issue.


Concrete Example

Step 1: Use a “firstValid” Aggregator

Here’s an example transformation definition in IdentityNow (in JSON). Notice how "bar" is defined with a firstValid aggregator. That aggregator tries a primary value, and if that primary value is empty, it uses "none" instead:

{
  "name": "foo",
  "type": "static",
  "attributes": {
    "bar": {
      "type": "firstValid",
      "attributes": {
        "values": [
          {
            "attributes": {
              "id": "Get Something"
            },
            "type": "reference"
          },
          "none"
        ]
      }
    },
    "value": "#if($bar != 'none')$bar#end"
  }
}

What’s happening here?

  1. The transformation tries to retrieve a value from "Get Something".
  2. If that result is not empty, $bar ends up holding that value.
  3. If that result is empty, the firstValid aggregator says “Use the next item in the list,” which is "none".

Hence $bar will always be either the real text or the string "none".

Step 2: Write Your Velocity Template Safely

Inside the "value" attribute, we have this Velocity snippet:

#if($bar != 'none')
  $bar
#end
  • If $bar was a legitimate string, we’ll print it.
  • If $bar was empty, then it becomes "none". The #if($bar != 'none') check fails, so nothing prints—but crucially, we do not crash the template by referencing a non-existent variable.

Layman’s Takeaway

  1. IdentityNow will not pass an attribute into Velocity if the attribute’s value is empty.
  2. Velocity will complain (or do unexpected things) if you reference a variable that doesn’t exist.
  3. To fix this, use a fallback: if your dynamic attribute is empty, automatically replace it with some placeholder (like "none").
  4. Now, Velocity always sees a real variable, so you can safely do #if($bar != "none").

That’s basically why the “layer of indirection” is needed. It’s not just extra complexity for the sake of it; it’s because under the hood, IdentityNow chooses not to inject empty values into Velocity, and that can crash or confuse your template. By explicitly returning a placeholder ("none") instead of an empty string, your template logic stays in control and avoids errors.

Hope this helps

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.