None entity_id in script?

Can you provide a small, reproducible test case that shows the change in behavior, as well as let me know what version it last used to work and what version it no longer works in?

1 Like

not really sure if I can, but ive never had any issues with this order of things until I noticed yesterday, apparently when no lights where on and the script got called in my scenario.

this:

  sequence:
    service: light.turn_off
    data_template:
      entity_id: >
        {% set ns = namespace(group=[]) %}
        {% if is_state('group.daughter','not_home') %}
          {% set ns.group = expand(states.group.all_inside_lights) %}
        {% else %}
          {% set ns.group = expand(states.group.all_main_inside_lights) + expand(states.group.plafond_spots_woonkamer) %}
        {% endif %}
        {% set all_lights_on =
         ns.group|selectattr('state','eq','on')|map(attribute='entity_id')|list|join(',') %}
        {{all_lights_on}}

is the first script.lighting_slapen in the ‘mother’ script.scene_slapen:

scene_slapen:
  alias: Call Slapen scene
  sequence:
    - service: script.lighting_slapen   # <---- this is the script posted above, and which errored out, causing the rest not to be executed all of a sudden....
    - service: input_boolean.turn_on
      entity_id:
        - input_boolean.home_mode_locked
        - input_boolean.ok_turn_off_audio_system
    - service: input_boolean.turn_off
      entity_id: input_boolean.early_night
    - delay:
        seconds: 5
    - service: switch.turn_on
      entity_id: switch.master_bedroom_motion_sensor_switch
    - service: script.set_hue_sensitivity_direct
      data:
        id: 48
        sensitivity: 0

though @petro found some ‘goofy crap’ I’ve copied the original in the template editor just now, which works just fine, if lights are on:


calling this script turns off these lights and then continues with step 2 etc, which also has been working like this since forever.

yesterday suddenly stopped it working, both the first subscript, (only reason why I can imagine is no lights were on, and the template rendering nothing, which probably is an invalid entity_id, as the error I posted displayed)
and the rest of the mother script, which simply wasn’t executed without further errors whatsoever.

About HA version: I am not 100% certain, but I am on 107.5 Hassio still. Wouldn’t know if this is the version it started with, because, as said, I think it only happened because of the no lights on situation in step 1 of the script, and that doesnt happen too often.

Would this be enough for you to investigate further? Let me know what else I could post to further assist.

Thanks for having a look!

btw, here’s the same template and the one @petro corrected, they show the same lights with ‘on’ lights:

Ok, I tried to reproduce with the following test case:

input_boolean:
  test:
    initial: off
light:

and these scripts:

test1:
  sequence:
  - service: light.turn_on
    data_template:
      entity_id: >
        {{ '' }}
test2:
  sequence:
  - service: script.test1
  - service: input_boolean.turn_on
    entity_id: input_boolean.test

I ran it in both HA 0.106.6 (the last release before any of the scripting changes I made) and 0.107.5. They both behaved exactly the same when I ran script.test2; i.e., the call to light.turn_on in script.test1 caused an error which also stopped script.test2 from continuing on to the second step, and hence input_boolean.test remained off.

but that’s not good is it? The master script should keep going even if one of the sub scripts causes an error? That’s the elegance of the use of subscripts…make the main script/automation robust

have another example with which I am struggling as I write this:

  - alias: 'GitHub repo update'
    trigger:
      platform: event
      event_type: state_changed
    condition:
      - condition: template
        value_template: >
          {{trigger.event.data.entity_id.startswith('sensor.github')}}
      - condition: template
        value_template: >
          {{'old_state' in trigger.event.data and 'new_state' in trigger.event.data and
            trigger.event.data.new_state.attributes.latest_release_url !=
            trigger.event.data.old_state.attributes.latest_release_url}}
    action:
      - service: notify.system
        data_template:
          title: Github repo update full
          message: >
           {{state_attr(trigger.event.data.entity_id,'name')}} was updated to {{state_attr(trigger.event.data.entity_id,'latest_release_url').split('tag/')[1]}}.
           Visit the release page {{state_attr(trigger.event.data.entity_id,'latest_release_url')}} to download.
      - service: input_boolean.turn_on
        data_template:
          entity_id: >
            input_boolean.github_{{state_attr(trigger.event.data.entity_id,'name').replace(' ','_')|lower}}  ##<--- can get this right
      - service: input_boolean.turn_on ##<---- so this isn't executed.....
        entity_id: input_boolean.github_repo_update

      - service: script.notify_github_update
        data_template:
          repo: >
            {{state_attr(trigger.event.data.entity_id,'name')}}
          url: >
            {{state_attr(trigger.event.data.entity_id,'latest_release_url')}}
          tag: >
            {{state_attr(trigger.event.data.entity_id,'latest_release_url').split('tag/')[1]}}

cant find the correct syntax for the second action , the template to take the triggering object_id to be added to the ‘input_boolean.github_’{{object_id}}.

I’ve also tried:

data_template:
          entity_id: >
            input_boolean.{{trigger.event.data.entity_id.object_id}}

or

 input_boolean.{{state_attr(trigger.event.data.entity_id ,'object_id'}} 

which causes the rest off the script to halt. It shouldn’t… I know automation passed up to the first action, and hence the trigger and the conditions are met, because I get a fine notification with the perfect text, and link in the message body.

fyi the triggering sensor is of format sensor.github_home_assistant, and I need it to set the input_boolean.github_home_assistant.

started it all with

          entity_id: >
            input_boolean.{{trigger.event.data.object_id}}

which I would have thought to be correct. I must be missing the obvious…

All I’m saying is the changes I recently made to the scripting infrastructure, under balloob’s supervision and approval, did not cause the behavior of your scripts to change. A “subscript” failing causes the calling script to fail, which is the same before and after the recent changes.

Should it work that way? I don’t know. All I can say is it does, and has.

Regarding the problem you can’t solve, how about:

input_boolean.{{ trigger.event.data.entity_id.split('.', 1)[1] }}
1 Like

Thanks Phil,

What ever the reason for these issues, it is caused only recently, because it also happens in the scripts and automations that drive my HA system for over almost 3 years now, and have been working perfectly since.

check this error, which I cant understand at all, because of the statement it is looking for an atttribute ‘is_on’. Which isn’t in the automation at all…:

2020-04-06 07:22:52 ERROR (MainThread) [homeassistant.components.automation] Activity selection: Error executing script. Unexpected error for call_service at pos 1: 'NoneType' object has no attribute 'is_on'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 138, in _async_step
    self, f"_async_{cv.determine_script_action(self._action)}_step"
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 233, in _async_call_service_step
    context=self._context,
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 101, in async_call_from_config
    domain, service_name, service_data, blocking=blocking, context=context
  File "/usr/src/homeassistant/homeassistant/core.py", line 1234, in async_call
    await asyncio.shield(self._execute_service(handler, service_call))
  File "/usr/src/homeassistant/homeassistant/core.py", line 1257, in _execute_service
    await handler.func(service_call)
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 207, in service_handler
    await script.async_turn_on(variables=service.data, context=service.context)
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 284, in async_turn_on
    await self.script.async_run(kwargs.get(ATTR_VARIABLES), context)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 693, in async_run
    await run.async_run()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 444, in async_run
    await self._async_run()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 460, in _async_run
    await self._async_step(not propagate_exceptions)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 138, in _async_step
    self, f"_async_{cv.determine_script_action(self._action)}_step"
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 233, in _async_call_service_step
    context=self._context,
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 101, in async_call_from_config
    domain, service_name, service_data, blocking=blocking, context=context
  File "/usr/src/homeassistant/homeassistant/core.py", line 1234, in async_call
    await asyncio.shield(self._execute_service(handler, service_call))
  File "/usr/src/homeassistant/homeassistant/core.py", line 1257, in _execute_service
    await handler.func(service_call)
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 207, in service_handler
    await script.async_turn_on(variables=service.data, context=service.context)
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 284, in async_turn_on
    await self.script.async_run(kwargs.get(ATTR_VARIABLES), context)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 693, in async_run
    await run.async_run()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 444, in async_run
    await self._async_run()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 460, in _async_run
    await self._async_step(not propagate_exceptions)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 138, in _async_step
    self, f"_async_{cv.determine_script_action(self._action)}_step"
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 233, in _async_call_service_step
    context=self._context,
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 101, in async_call_from_config
    domain, service_name, service_data, blocking=blocking, context=context
  File "/usr/src/homeassistant/homeassistant/core.py", line 1234, in async_call
    await asyncio.shield(self._execute_service(handler, service_call))
  File "/usr/src/homeassistant/homeassistant/core.py", line 1257, in _execute_service
    await handler.func(service_call)
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 204, in service_handler
    if script.is_on:

and this is the automation:

automation:

  - alias: 'Activity selection'
    id: 'Activity selection'
    trigger:
      platform: state
      entity_id: input_select.activity
    condition:
      condition: template
      value_template: >
        {{states('input_select.activity') in
          ['Opstaan','Aan de slag','Home theater',
           'Gym','Gaming','Selamat makan','Naar bed','Slapen']}}
    action:
      - service_template: >
          script.{{trigger.to_state.state|lower|replace(' ','_')}}
      - service: python_script.summary_mode_activity

also, some change must have been made, because, as said, the main reason to write these automation and scripts using subscripts in the action block has always been the fact of robustness and the main script being able to continue, even if a subscript for whatever reason errors out.

Added to the above issue, this is also in the logs:

the exact same error, but, this is logged for my ‘Slapen’ activity, which was called yesterday night. Note that it apparently has been trying to keep running the script, at least until 7.22.52 this morning! So first the script errors, and halts the full ‘mother’ script. Secondly, it keeps trying to run somehow…

all very new behavior, and must be said, unwanted behavior…

It looks like your automation is calling a script, which calls a script, which attempts to call yet another script that doesn’t exist. What are the lines preceding the error message? It should give you an indication of what other scripts it is trying to call which should help you to narrow down what script is being called that doesn’t exist. It might also help to add the following to your logger config:

homeassistant.core: debug

I don’t know what to tell you other than what I already have.

That’s not helpful. I’ve already said that I tested your error case and it works now like it did before my recent changes. There may have been other changes before that that have contributed to what you see as a change of behavior, but you’re not helping to narrow down what those changes might be. I can’t reproduce and test huge automation/scripting infrastructures. You need to create a reproducible test case and you’ll have to determine/prove when it did work (i.e., in which previous version) and when it stopped working if you want any progress to be made.

That’s definitely a change in ‘default’ behaviour. Maybe not by your changes, but a change to default nevertheless.

What should happen if you run script.test2 in that scenario is that the input_boolean always turns on.

It’s what we’ve been telling people to do for years.

Test2 should fire script test1 and then continue to the input_boolean service regardless of the completion of test1.

exactly! and it was default behavior until very recently, a change has certainly be made, purposely or not.

I can confirm with @anon43302295 and @Mariusthvdb, nested scripts have been used (and I used them at one point) to keep the main script running if the sub scripts error.

I’m remembering wrong.

Ok, I hear you, it changed. But if anyone would like my help to figure out what changed it when I’ll need more details, and/or a better (reproducible) test case. I already went back to 0.106.6, which as I said, was before the recent change to the script “helper”, and it behaved then as it does now.

Actually. I take back my response.

I was miss remembering conditions inside scripts. I haven’t had to use them for actual errors occuring on service calls.

1 Like

Also, I don’t think you should take back your work. I think new behavior in regards to errors in scripts should be investigated. I don’t see why we errored in the first place if a light didn’t actually change. Why care, just move on.

fwiw, I am not suggesting at all Phil should take back his work. I am convinced if Phil says this has nothing to do with erroring subscripts causing a main script to halt, he is right.

I do agree this issue should be investigated though. And that it is new. cant explain otherwise that automations and scripts the have been working for years now, would suddenly start acting up.

Would start doubting myself for changing template conditions to state conditions (as advised by Phil himself in another thread) but the automation posted above doesnt use these, so that can’t be it either…

thing is, don’t know where to look, because the script mentioned in the error, script.is_on doesn’t exist in my setup, not is there a template that would create that script. The error is most unexpected.

debug is on, and hope to be able to report more later on.

That’s not the name of a script. That is a method of the ScriptEntity class. Here’s the code (which, BTW, is not part of the changes so far):

    async def service_handler(service):
        """Execute a service call to script.<script name>."""
        entity_id = ENTITY_ID_FORMAT.format(service.service)
        script = component.get_entity(entity_id)
        if script.is_on:
            _LOGGER.warning("Script %s already running.", entity_id)
            return
        await script.async_turn_on(variables=service.data, context=service.context)

What’s happening is the entity_id of the script being called is passed to component.get_entity(entity_id), but it doesn’t find it (because it doesn’t exist), and it returns None. Then the code tries to call the is_on method without checking if script is None (or without enclosing it in a try block), which then causes the exception you’re seeing.

As I said before, the lines before the error/exception (in home-assistant.log) should tell you what the name of the script was that it was trying to call.

1 Like

I see, thanks for explaining (again)…

Didn’t happen last night, so can’t reproduce the exact issue right now. I did change the script in the topic of this thread to be a simple variant:

turn_off_all_lights:
  alias: Turn off all lights
#Turn off all lights with transition, causes automatic turn_on to use brightness 0% next time, so taken out
  sequence:
    service: homeassistant.turn_off
    data_template:
      entity_id: >
        {% if is_state('group.hanna','not_home') %}
          group.all_inside_lights
        {% else %}
          group.all_main_inside_lights, group.plafond_spots_woonkamer
        {% endif %}
#     transition: 6

not sure if that could have caused it before, if I test the scripts I had, and @petro’s improved version, I don’t see the error in the log now.

Will keep on bug hunting.

As for the general issue of a failing script to halt the containing script: how to proceed with that issue?

sorry, forgot to repond to this.
you are right, that works ok.

I’ve tested with:

          message: >
           {{state_attr(trigger.event.data.entity_id,'name')}} was updated to {{state_attr(trigger.event.data.entity_id,'latest_release_url').split('tag/')[1]}}.
           Visit the release page {{state_attr(trigger.event.data.entity_id,'latest_release_url')}} to download.
           Object is {{trigger.event.data.object_id}}
           Entity is {{trigger.event.data.entity_id}}
           Name is {{state_attr(trigger.event.data.entity_id,'name')}}
           Fake Object is {{trigger.event.data.entity_id.split('.')[1]}}

and the message is clear on all templates, except for the one using object_id, which simply results in an empty field:
Object is

all others show the expected outcome. Why cant we use object_id here? State objects - Home Assistant would suggest otherwise, and in regular jinja templates I do so without issue.

about your format:

{{ trigger.event.data.entity_id.split('.', 1)[1] }}

what does the 1 in split('.', 1) do? I think I get the same result without it?

splits a maximum of 1 time on the first occurrence.

Since it’s a state_changed event you can. You just have to get it from the correct place:

{{ trigger.event.data.new_state.object_id }}
2 Likes

So some additional thoughts…

First, a script (or automation action sequence) calls another script in a blocking fashion, which means if an exception happens during the “subscript” it will also abort the calling script, just like any other service called. However, if the subscript hits a delay step, or a wait_template step that actually waits, then the subscript will “suspend” and “return” to the calling script/automation, which will continue to the next step. In this scenario, if the subscript fails (e.g., causes an exception) after the delay or wait_template step, the script/automation that originally called it will not be affected. This must be what y’all are thinking of.

With that in mind, one way to ensure a calling script/automation will continue even if a called subscript fails is to put a “delay zero” step at the beginning of the subscript:

xyz:
  sequence:
  - delay: 0
  - ...

That will cause the subscript to immediately suspend and return to the calling script, and then start again (in parallel with the calling script, assuming it’s still running) within one second.

And as to the exception caused by the subscript not existing, I realized that shouldn’t be possible, because if you call a script via “service: script.NAME” (or even via a service_template), and that script didn’t exist, a service by its name would not have been registered and, hence, you’d get a “service not found” error (long before the exception would happen.) That reminded me of an issue that was raised about a bug, specifically 25419 " script.reload while script is running". (And @Mariusthvdb you even commented on that issue. :slightly_smiling_face:) I’ve fixed the bug, but haven’t submitted the fix yet because it was going to be part of the larger scripting rewrite which, unfortunately, has been taking a lot longer than I had originally hoped.

With that in mind, don’t reload scripts while any of them are running. If you can’t prevent them from running while you reload them, then restart HA instead.

2 Likes