Trigger-based template sensors: are attributes mixed with variables?

I was trying to debug a strange problem with one of my template sensors and it seems to be caused by the fact that when defining an attribute, you can reference other attributes directly, and they get mixed up with variables. I’m sure this wasn’t the case a few months ago - unless I was hit by the Mandela Effect.

Example:

  1. create this template sensor
- trigger:
    - trigger: event
      event_type: my_custom_event
      id: config
  sensor:
    - name: Is ths a bug?
      state: "{{ trigger.event.data.some_value }}"
      attributes:
        a1: "{{ trigger.event.data.some_value }}"
        a2: "{{ a1 }}"
        trigger: Hi Bob!
        a3: "{{ trigger.event.data.some_value if trigger.event is defined else 'Uh oh!' }}"
        a4: "{{ trigger }}"
  1. reload templates, the sensor will have no state and no attributes, as expected:

  1. send an event my_custom_event with data field some_value: 34

Results:

  1. attribute a1 shows the value from trigger.event.data.some_value - OK
  2. attribute a2 references a1 as if it was a variable, and gets the new value - WEIRD
  3. attribute trigger has a static text - OK
  4. attribute a3 tries to reference trigger variable (like a1 before) but that variable is now hidden by the attribute named trigger - SUPER WEIRD
  5. attribute a4 confirms the new value associated with “trigger”

Trigger is a variable and you are overwriting it.
That is pretty much it.

1 Like

Yes I get it but is it like a recent thing? I’m pretty sure in the past you’d have to use e.g. this.attributes.a1 to reference another attribute, and it would give you the old/previous value (taken from the not-yet-updated state object)

No this is not recent, I’m pretty sure this is how it has always worked.
Why do you need to create an attribute with the name trigger?
There must me millions of other options to use as the attribute name

I don’t need to, I just had an attribute like this to store the ID of the last trigger fired. I think my sensor used to work correctly with that attribute, but I’m no longer sure :slight_smile: Anyway, thanks!

Wow. Not something I would have expected. Why would attributes get scoped locally like variables? Why would they become variables at all? I guess it could be handy. Maybe.

It still freaks me out you can even do this:

variables:
    foo: "{{ 123 }}"
    bar: "{{ foo }}"

as I was raised back when you never trusted the order of processing in dictionaries…

Right? This is strange and dangerous, to say the least. I also remember reading old threads where people resorted to various gymnastics to read the values ​​of other attributes. But now I assume such syntax always existed and I just never encountered it.

That’s seems pretty messed up to me that attributes would behave like variables, and I just scoured the template and sensor docs and there’s nothing to suggest you’d have to be careful of this. Might help me understand why a template sensor that I have that pulls it’s state from an attribute using this.attributes suddenly borked on me with this month’s update, will have to investigate. Edit: that was not it

I’d love to have Petro weigh in on this behaviour.

Indeed. For example:

  - triggers:
      - trigger: event
        event_type: my_custom_event
        id: config
    variables:
      now: "{{ now() }}"
    sensor:
      - name: Is ths a bug?
        state: "{{ trigger.event.data.some_value }}"
        attributes:
          now: "Now is apparently {{ now }}"
          saved_time: "{{ now }}"

Results in:

friendly_name: Is ths a bug?
now: Now is apparently 2026-02-21 12:04:27.365531-08:00
saved_time: Now is apparently 2026-02-21 12:04:27.365531-08:00
1 Like

This is not weird at all. Seems perfectly logical. You only have one type of named variable. If you reuse variable names the data will be over written.

Don’t reuse the name if you don’t want this to happen.

But an attribute is not a variable! :slight_smile: And now I have proof that wasn’t always the case: the same sensor in core version 2025.4.4 produced this result:

and a warning in the logs:
Template variable warning: 'a1' is undefined when rendering '{{ a1 }}'

Last year I updated core from version 2025.4.x → 2025.8.x → 2025.12.x. The change occurred (quietly?) sometime between April and August.

A named variable is a named variable. Attribute or otherwise.

This is probably a consequence of increasing the scope of variables last year. Which was a good thing (pros far outweigh cons). It was in the release notes.

EDIT: first one here: 2025.4 Time to continue the dashboards! - Home Assistant

image

Adding the keys of variables into the local scope seems very different than localizing keys of unrelated dictionaries into the same namespace as the variables.

But variables are named variables. In this case these keys are even nested one level down below sensor:

And in this example:

actions:
    - variables:
         foo: Bla Bla
         entity_id: light.some_room
    - action: light.do_something
      target:
          entity_id: light.other_room
       data:
           extra_stuff:
               foo: Is this a new foo?

Are those also variables? You would never expect entity_id or foo to be replaced here, right?

It couldn’t have been that change, because I just presented a proof from the very version you cited (2025.4.4). And in that version, the attribute isn’t considered a variable:

      attributes:
        a1: "{{ trigger.event.data.some_value }}"
        a2: "{{ a1 }}"

results in Template variable warning: 'a1' is undefined when rendering '{{ a1 }}'

Look, I’m not against change or anything, I just wish there weren’t surprises like this.

This is by design and it’s not recent. It’s worked this way since attributes were added. You’re miss remembering something.

I took over template entities 2 years ago and I haven’t changed that section of code. I added test cases in the past year to ensure the behavior you’re describing here works.

1 Like

Anything you access via {{ some_name }} is a variable.

No! I just showed you the proof, didn’t I? Now I feel like I’m being gaslighted :slight_smile:
I checked the actual version when this change happened and it was 2025.5.3. I found no mention in the release notes of attributes becoming variables in this version.

I also checked 2025.3.4 just to be sure, and again the attribute name isn’t recognized as variable, as in 2025.4.4. So please don’t tell me I’m miss remembering, because at this stage it’s not very pleasant.

Well, yeah. But that’s not what this is referring to.

Another counter example:

actions:
  - variables:
      foo: 1234
  - event: my_event
    event_data:
       foo: hello
       var_foo: "{{ foo }}"

Results in foo not being overwritten. I’m trying to see the difference.

event_type: my_event
data:
  foo: hello
  var_foo: 1234
origin: LOCAL
time_fired: "2026-02-21T22:35:03.428757+00:00"
context:
  id: 01KJ15F4W32MBY4NGJ5F7DNS81
  parent_id: 01KJ15F4W2CG495J9JC0NVR440
  user_id: null

Could it be that your attributes in the yaml was in a different order?

Try this:

- trigger:
    - trigger: event
      event_type: my_custom_event
      id: config
  sensor:
    - name: Is ths a bug?
      state: "{{ trigger.event.data.some_value }}"
      attributes:
        a1: "{{ trigger.event.data.some_value }}"
        a2: "{{ a1 }}"
        a3: "{{ trigger.event.data.some_value if trigger.event is defined else 'Uh oh!' }}"
        a4: "{{ trigger }}"
        trigger: Hi Bob!

I’ve been making both state based template entities and trigger based entities work the same way. It’s possible that trigger based entities had a bug where they didn’t act like state based entities. But the intention of attributes has always been a waterfall where the previously defined attribute is usable in the next.