Variable is referenced before assignment but not everywhere

Hello.

I am writing my first workflow and I have a really weird issue.

There is the code :

version: 1.0

input:
  - remote_address

tasks:
  # [513, 91]
  get_bgp_session:
    action: librenms.get_bgp_sessions
    input:
      log_level: DEBUG
      remote_address: <% ctx().remote_address %>
      debug: false
    next:
      - do:
          - get_l2_ipv6_device
        when: <% ":" in result().result.bgp_sessions[0].bgpLocalAddr %>
        publish:
          - address: <% result().result.bgp_sessions[0].bgpLocalAddr %>
      - do:
          - get_l3_ipv4_device
        when: <% "." in result().result.bgp_sessions[0].bgpLocalAddr %>
        publish:
          - address: <% result().result.bgp_sessions[0].bgpLocalAddr %>
      - do:
          - map_peer_ip_to_mac
        when: <% "." in result().result.bgp_sessions[0].bgpPeerIdentifier %>
        publish:
          - ip: <% result().result.bgp_sessions[0].bgpPeerIdentifier %>
  # [341, 200]
  get_l3_ipv4_device:
    action: librenms.get_devices
    input:
      log_level: DEBUG
      type: ipv4
      query: <% ctx().address %>
    next:
      - when: <% succeeded() %>
        publish:
          - l3_hostname: <% result().result[0].hostname %>
          - l3_interface: <% result().result[0].ifName %>
  # [104, 199]
  get_l2_ipv6_device:
    action: librenms.get_devices
    next:
      - when: <% succeeded() %>
        publish:
          - l3_hostname: <% result().result[0].hostname %>
          - l3_interface: <% result().result[0].ifName %>
    input:
      log_level: DEBUG
      type: ipv6
      query: <% ctx().address %>
  # [678, 203]
  map_peer_ip_to_mac:
    action: librenms.get_ip_arp
    input:
      log_level: DEBUG
      ip: <% ctx().ip %>
    next:
      - do:
          - get_path_to_peer
        publish:
          - mac: <% result().result.arp[0].mac_address %>
        when: <% result().result.arp %>
  # [679, 344]
  get_path_to_peer:
    action: librenms.get_fdb
    input:
      log_level: DEBUG
      mac: <% ctx().mac %>
    next:
      - do:
          - get_l2_port
        publish:
          - id: <% result().result.ports_fdb[0].port_id %>
      - do:
          - get_l2_device
        publish:
          - id: <% str(result().result.ports_fdb[0].device_id) %>
  # [794, 460]
  get_l2_port:
    action: librenms.get_port
    input:
      log_level: DEBUG
      port_id: <% ctx().id %>
    next:
      - when: <% succeeded() %>
        publish:
          - l2_interface: <% result().result.ifName %>
  # [547, 458]
  get_l2_device:
    action: librenms.get_device
    input:
      log_level: DEBUG
      id: <% ctx().id %>
    next:
      - when: <% succeeded() %>
        publish:
          - l2_hostname: <% result().result.devices[0].hostname %>
      

output:
  - l3_hostname: <% ctx().l3_hostname %>
  - l3_interface: <% ctx().l3_interface %>
  - l2_hostname: <% ctx().l2_hostname %>
  - l2_interface: <% ctx().l2_interface %>

The error I am getting is :

{
  "errors": [
    {
      "expression": "<% ctx().l2_hostname %>",
      "message": "Variable \"l2_hostname\" is referenced before assignment.",
      "spec_path": "output[2]",
      "schema_path": "properties.output",
      "language": "yaql",
      "type": "context"
    },
    {
      "expression": "<% ctx().l2_interface %>",
      "message": "Variable \"l2_interface\" is referenced before assignment.",
      "spec_path": "output[3]",
      "schema_path": "properties.output",
      "language": "yaql",
      "type": "context"
    }
  ],
  "output": null
}

I don’t understand why l2 outputs are having those issues where l3 are defined exactly the same way and are working fine.

Any idea of what could be the issue ?

Thanks.

  get_l2_ipv6_device:
    action: librenms.get_devices
    next:
      - when: <% succeeded() %>
        publish:
          - l3_hostname: <% result().result[0].hostname %>
          - l3_interface: <% result().result[0].ifName %>

Is this task suppose to publish l2_hostname and l2_interface instead of l3_hostname and l3_interface?

Also, since get_path_to_peer only runs on certain condition when <% result().result.arp %>, it’s on a different branch. Even if l2_hostname and l2_interface are defined there, the default branch will not have those variables defined.

get_l2_ipv6_device is a typo, it should be get_l3_ipv6_device :slight_smile:

So the workflow engine detect that it can potentially miss the variables and then refuse to run it ?
How to workaround this ? Can I define default values for those output variables ?

The detection is there to ensure correctness. If the workflow is run and access the variable before it is assigned, it will result in exception anyway. You can use the vars section of the workflow definition to assign default values for variables.