Hue scene setup error on restart caused by bridge_home scenes (/groups/0)
I ran into a Home Assistant Hue integration startup error where several Hue scenes failed to create as HA scene entities.
I'm NOT going to file this as a issue on GitHub (there are more important Hue things to get into HA than this - such as #151883 and #156617...) but it's here for reference if anyone ever hits it.
Environment
- Home Assistant: 2026.5.2
- Install type: Home Assistant Container
- Hue integration: built-in Philips Hue integration
- Multiple Hue bridges
Error seen in Home Assistant logs
On restart I saw errors like this:
Logger: homeassistant.components.hue.scene
Source: components/hue/scene.py:61
Integration: Philips Hue
Unable to create Hue scene entity for <scene UUID>
Unable to create Hue scene entity for <scene UUID>
Unable to create Hue scene entity for <scene UUID>
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/hue/scene.py", line 61, in async_add_entity
entity = HueSceneEntity(bridge, api.scenes, resource)
File "/usr/src/homeassistant/homeassistant/components/hue/scene.py", line 112, in __init__
self.hue_group = self.controller.get_group(self.resource.id)
File "/usr/local/lib/python3.14/site-packages/aiohue/v2/controllers/scenes.py", line 100, in get_group
return next(x for x in self._bridge.groups if x.id == scene.group.rid)
StopIteration
This didn't appear to be causing ANY problems at all other than this annoying error report in the HA logs after every restart.
Root cause found
The failing scenes were valid Hue scenes, but they were not attached to a normal Hue room or zone.
They were attached to the Hue v2 bridge_home resource, which maps to the old Hue v1 /groups/0 whole-bridge group.
In my case the scenes were the standard Hue recipe scenes:
Concentrate
Energize
Nightlight
Read
Relax
The bridge returned them as scenes with:
group.rtype = bridge_home
group.rid = <bridge_home UUID>
id_v1 = /scenes/<id>
The corresponding bridge_home resource had:
type = bridge_home
id_v1 = /groups/0
So it looks as if Home Assistant/aiohue tries to resolve the scene group through the normal room/zone group collection, but bridge_home is not found there, causing the StopIteration.
How these got here - who knows, but I suspect they could be from:
- Setting up a whole home scene on Hub v1 (can't remember doing that but perhaps)
- Some old Hue labs code
- Someone setting up a dimmer to apply a scene across the whole house and then reversing it (probably me)
- As a result of the migration process from Old Hub to Pro this may have been carried into v2
- Some combination of all the above in a hand waving way of justifying it
Either way I couldn't find a way to remove them in the current Hue app.
Why this was hard to track down
The Home Assistant diagnostics redacted the primary resource IDs, so searching the diagnostics file for the failing scene UUIDs from the log did not work.
The Hue bridge API still had the real scene IDs, so querying the bridge directly was the easiest way to map the log UUIDs back to human-readable scene names.
Example bridge-home output
I have several Hue bridges. Only one bridge had scenes attached to bridge_home.
Example output, with bridge names, IP addresses, and some IDs anonymised:
====================================================================================================
Bridge: Bridge A
Host: 10.x.x.x
bridge_home id: <bridge_home UUID>
bridge_home id_v1: /groups/0
bridge_home name: <unnamed>
Children:
device <device UUID> Bridge A
room <room UUID> Room 1
room <room UUID> Room 2
room <room UUID> Room 3
room <room UUID> Room 4
room <room UUID> Room 5
Services:
grouped_light <grouped_light UUID> /groups/0
grouped_motion <grouped_motion UUID>
grouped_light_level <grouped_light_level UUID>
Scenes attached to bridge_home:
<scene UUID> Concentrate id_v1=/scenes/<id>
<scene UUID> Energize id_v1=/scenes/<id>
<scene UUID> Nightlight id_v1=/scenes/<id>
<scene UUID> Read id_v1=/scenes/<id>
<scene UUID> Relax id_v1=/scenes/<id>
====================================================================================================
Bridge: Bridge B
Host: 10.x.x.x
bridge_home id: <bridge_home UUID>
bridge_home id_v1: /groups/0
bridge_home name: <unnamed>
Scenes attached to bridge_home:
<none>
====================================================================================================
Bridge: Bridge C
Host: 10.x.x.x
bridge_home id: <bridge_home UUID>
bridge_home id_v1: /groups/0
bridge_home name: <unnamed>
Scenes attached to bridge_home:
<none>
Script 1 — map failing scene UUIDs to names
Run this inside the Home Assistant container from /config to just confirm you are matching those UUIDs from the HA error log against this problem. Helps make sure this is the issue and that you are running these scripts in the right place!
Edit BAD_SCENES and put in the scene UUIDs from your HA log.
#!/usr/bin/env python3
import json
import ssl
import urllib.request
from pathlib import Path
BAD_SCENES = {
"PUT-SCENE-UUID-HERE",
"PUT-SCENE-UUID-HERE",
}
CONFIG = Path("/config/.storage/core.config_entries")
ctx = ssl._create_unverified_context()
def get_json(host, key, path):
req = urllib.request.Request(
f"https://{host}/clip/v2/resource/{path}",
headers={"hue-application-key": key},
)
with urllib.request.urlopen(req, context=ctx, timeout=10) as r:
payload = json.load(r)
if payload.get("errors"):
raise RuntimeError(payload["errors"])
return payload.get("data", [])
with CONFIG.open() as f:
entries = json.load(f)["data"]["entries"]
for entry in entries:
if entry.get("domain") != "hue":
continue
data = entry.get("data", {})
title = entry.get("title") or entry.get("entry_id")
host = data.get("host")
key = (
data.get("api_key")
or data.get("application_key")
or data.get("username")
)
print()
print("=" * 80)
print(f"Entry: {title}")
print(f"Host: {host}")
if not host or not key:
print("Missing host or Hue application key in this config entry")
continue
try:
scenes = {s["id"]: s for s in get_json(host, key, "scene")}
rooms = {r["id"]: r for r in get_json(host, key, "room")}
zones = {z["id"]: z for z in get_json(host, key, "zone")}
bridge_homes = {h["id"]: h for h in get_json(host, key, "bridge_home")}
except Exception as e:
print(f"Could not query bridge: {e}")
continue
found_any = False
for scene_id in BAD_SCENES:
scene = scenes.get(scene_id)
if not scene:
continue
found_any = True
group = scene.get("group", {})
group_id = group.get("rid")
group_type = group.get("rtype")
if group_type == "room":
group_resource = rooms.get(group_id)
elif group_type == "zone":
group_resource = zones.get(group_id)
elif group_type == "bridge_home":
group_resource = bridge_homes.get(group_id)
else:
group_resource = None
scene_name = scene.get("metadata", {}).get("name", "<unnamed scene>")
group_name = (
group_resource.get("metadata", {}).get("name")
if group_resource
else "<missing group>"
)
print()
print(f"Scene ID: {scene_id}")
print(f"Scene name: {scene_name}")
print(f"Group: {group_type} {group_id}")
print(f"Group name: {group_name}")
if not found_any:
print("None of the failing scene IDs are on this bridge")
Script 2 — print bridge_home resources and scenes on all your Hue bridges
This helped confirm that only one bridge had scenes attached to bridge_home for me - but you may have it on more than one - but at least you will be able to see from this output.
#!/usr/bin/env python3
import json
import ssl
import urllib.request
from pathlib import Path
CONFIG = Path("/config/.storage/core.config_entries")
ctx = ssl._create_unverified_context()
def get_json(host, key, resource):
req = urllib.request.Request(
f"https://{host}/clip/v2/resource/{resource}",
headers={"hue-application-key": key},
)
with urllib.request.urlopen(req, context=ctx, timeout=10) as r:
payload = json.load(r)
if payload.get("errors"):
raise RuntimeError(payload["errors"])
return payload.get("data", [])
def name_of(obj):
return obj.get("metadata", {}).get("name", "<unnamed>")
with CONFIG.open() as f:
entries = json.load(f)["data"]["entries"]
for entry in entries:
if entry.get("domain") != "hue":
continue
title = entry.get("title") or entry.get("entry_id")
data = entry.get("data", {})
host = data.get("host")
key = data.get("api_key") or data.get("application_key") or data.get("username")
print()
print("=" * 100)
print(f"Bridge: {title}")
print(f"Host: {host}")
if not host or not key:
print("Missing host or Hue application key")
continue
try:
bridge_homes = get_json(host, key, "bridge_home")
rooms = {r["id"]: r for r in get_json(host, key, "room")}
zones = {z["id"]: z for z in get_json(host, key, "zone")}
devices = {d["id"]: d for d in get_json(host, key, "device")}
scenes = get_json(host, key, "scene")
grouped_lights = {g["id"]: g for g in get_json(host, key, "grouped_light")}
except Exception as e:
print(f"ERROR querying bridge: {e}")
continue
if not bridge_homes:
print("No bridge_home resource found")
continue
for home in bridge_homes:
home_id = home["id"]
print()
print(f"bridge_home id: {home_id}")
print(f"bridge_home id_v1: {home.get('id_v1', '<none>')}")
print(f"bridge_home name: {name_of(home)}")
print()
print("Children:")
for child in home.get("children", []):
rid = child.get("rid")
rtype = child.get("rtype")
if rtype == "room":
label = name_of(rooms.get(rid, {}))
elif rtype == "zone":
label = name_of(zones.get(rid, {}))
elif rtype == "device":
label = name_of(devices.get(rid, {}))
else:
label = "<unknown>"
print(f" {rtype:8} {rid} {label}")
print()
print("Services:")
for service in home.get("services", []):
rid = service.get("rid")
rtype = service.get("rtype")
if rtype == "grouped_light":
svc = grouped_lights.get(rid, {})
label = svc.get("id_v1", "") or name_of(svc)
else:
label = ""
print(f" {rtype:20} {rid} {label}")
print()
print("Scenes attached to bridge_home:")
home_scenes = [
s for s in scenes
if s.get("group", {}).get("rid") == home_id
and s.get("group", {}).get("rtype") == "bridge_home"
]
if not home_scenes:
print(" <none>")
else:
for s in sorted(home_scenes, key=lambda x: name_of(x).lower()):
print(f" {s['id']} {name_of(s)} id_v1={s.get('id_v1', '<none>')}")
Script 3 — dry-run and optionally delete stranded bridge_home scenes
The fix. save this script in your /config directory and again run it from inside the container - I called it tidy_hue_bridge_home_scenes.py.
It checks whether the target scenes are still referenced by any Hue behavior_instance to make sure there isn't something in the Hue hub that is actually using these scenes (you may be on a Hue hub v1 which I haven't tested against, or have some dimmer switch that is set to apply to the whole home, or some hue labs thing still active).
Edit:
TARGET_BRIDGE - set it for the bridge you want to remove the scenes from
TARGET_SCENES - set up the scenes and UUID's that you want to remove
If you need to do this on more than one bridge - change them for each bridge and rerun the script.
It runs as a dry run by default. It only deletes if --delete is supplied as a command line argument.
#!/usr/bin/env python3
import argparse
import json
import ssl
import urllib.request
from pathlib import Path
TARGET_BRIDGE = "Bridge A"
TARGET_SCENES = {
"PUT-SCENE-UUID-HERE": "Scene name here",
"PUT-SCENE-UUID-HERE": "Scene name here",
}
CONFIG = Path("/config/.storage/core.config_entries")
ctx = ssl._create_unverified_context()
parser = argparse.ArgumentParser()
parser.add_argument("--delete", action="store_true", help="actually delete the scenes")
args = parser.parse_args()
def request(host, key, method, resource):
req = urllib.request.Request(
f"https://{host}/clip/v2/resource/{resource}",
headers={"hue-application-key": key},
method=method,
)
with urllib.request.urlopen(req, context=ctx, timeout=10) as r:
return json.load(r)
def get_data(host, key, resource):
payload = request(host, key, "GET", resource)
if payload.get("errors"):
raise RuntimeError(payload["errors"])
return payload.get("data", [])
def contains_scene_id(obj, scene_id):
if isinstance(obj, dict):
if obj.get("rid") == scene_id and obj.get("rtype") == "scene":
return True
return any(contains_scene_id(v, scene_id) for v in obj.values())
if isinstance(obj, list):
return any(contains_scene_id(v, scene_id) for v in obj)
return False
with CONFIG.open() as f:
entries = json.load(f)["data"]["entries"]
entry = next(
e for e in entries
if e.get("domain") == "hue"
and (e.get("title") or e.get("entry_id")) == TARGET_BRIDGE
)
data = entry["data"]
host = data["host"]
key = data.get("api_key") or data.get("application_key") or data.get("username")
print(f"Bridge: {TARGET_BRIDGE}")
print(f"Host: {host}")
print()
scenes = {s["id"]: s for s in get_data(host, key, "scene")}
behaviours = get_data(host, key, "behavior_instance")
for scene_id, expected_name in TARGET_SCENES.items():
scene = scenes.get(scene_id)
if not scene:
print(f"{scene_id} {expected_name}: already absent")
continue
actual_name = scene.get("metadata", {}).get("name", "<unnamed>")
group = scene.get("group", {})
refs = [
b for b in behaviours
if contains_scene_id(b, scene_id)
]
print("-" * 80)
print(f"Scene: {actual_name}")
print(f"ID: {scene_id}")
print(f"Group: {group.get('rtype')} {group.get('rid')}")
print(f"Refs: {len(refs)} behavior_instance reference(s)")
if refs:
print("NOT deleting because it is still referenced:")
for b in refs:
print(f" {b.get('id')} {b.get('metadata', {}).get('name', '<unnamed>')}")
continue
if args.delete:
result = request(host, key, "DELETE", f"scene/{scene_id}")
print("DELETE result:")
print(json.dumps(result, indent=2))
else:
print("Dry run only. Would delete with --delete.")
Run dry first:
python3 tidy_hue_bridge_home_scenes.py
If all target scenes show zero behavior_instance references, add the --delete argument:
python3 tidy_hue_bridge_home_scenes.py --delete
Then run dry again to confirm they have been deleted:
python3 tidy_hue_bridge_home_scenes.py
After deleting the stranded bridge_home scenes, re-running the script should show something like:
<scene UUID> Concentrate: already absent
<scene UUID> Energize: already absent
<scene UUID> Nightlight: already absent
<scene UUID> Read: already absent
<scene UUID> Relax: already absent
The Hue scene setup errors should now disappear on the next Home Assistant restart or Hue integration reload.
Notes / cautions
- Do not delete scenes unless you have confirmed they are not referenced by Hue
behavior_instance. - This only checks Hue bridge behaviours, not Home Assistant YAML/UI automations.
- Consider searching your Home Assistant config for the scene UUIDs before deleting them.
- I would treat this as a workaround, not necessarily the underlying fix.
- Home Assistant/aiohue may need to either ignore
bridge_homescenes or handle them explicitly instead of raisingStopIteration.