Issue with Matter on self hosted Homey

I have an OTBR running on Home Assistant and from day one I was facing the 0x00AC error.
What made this particularly frustrating is that sharing worked perfectly fine with my other border routers (Nest Hub and Homey Pro 2023). IPv6 in my setup was working correctly as well, and I could reach my Thread devices without issues using tools like NetShoot. So this was clearly not a “broken IPv6” or “basic network” problem.

To add some context about the environment: this SHS setup is running on a TrueNAS system on which I reliably host multiple apps and containers without any issues. This is a stable setup that has been in use for quite some time, not an experimental or misconfigured test environment.

After updating to v12.11, everything suddenly works flawlessly. I’m genuinely happy that I now finally have a fully working SHS.

That said, I do want to address the support experience, which I personally found disappointing.

After spending roughly two weeks actively following in multiple Matter and Thread-related forum topics, without any resolution, I decided to log a ticket with Homey. In my ticket, I explicitly stated that I had already searched and followed the forum extensively, and that there were multiple posts from users encountering the same 0x00AC error on different hosts.

The response I received was that Homey unfortunately could not provide support for my setup, that the 30-day trial exists for a reason, and that I should look on the forum for help, despite having clearly stated that I already did exactly that.

In my opinion, this is not customer-friendly, not to say arrogant.

What made it worse was that some forum members joined in by confidently stating that Homey could not possibly offer a solution here, and that the root cause must certainly be the user’s own installation or lack of knowledge. This was said without any understanding of the background or experience of the people they were responding to.

Everyone was a beginner at some point. Being addressed this way on a forum that is meant to help people is, frankly, discouraging.

For context: I installed my first Home Assistant instance back in 2014.
So yes, some of those comments were quite misplaced, and those members may feel addressed by this post.

I’m glad the issue is resolved with v12.11. I just hope that, going forward, both support responses and forum interactions can be handled with a bit more openness and respect, specially when multiple users report the same technical issue.

I completely agree. It was very poor.

In the forums I got the same response you did and on my support ticket an identical response. The Homey-SHS page states it supports Matter, but never did it mention I needed additional hardware for Thread. Maybe I could have known… but that set me back. Nevertheless I did have a Thread border router and it did not work. So the fact that I did not know that I needed it, made everyone say “you don’t understand how things work, it must be you”.

I started digging, but got lost since hardware I bought new (Matter-over-Wifi) did not work either… and now they said; “Yep! Confirmed! It’s your router, Docker config or you”.

This is the response I got in my support ticket:

… I understand the confusion about needing another hub other than the Homey Bridge to have a Thread border router.

The simplest answer is that this is a generational issue. The Homey Bridge does not support Matter/Thread and is equipped with a Zigbee 2.0 chip. The Homey Bridge arrived on the scene when Matter and Thread were still being developed and perhaps future generations will be able to act as border routers on their own.

For now this is all I can do for you, which is why I’m closing your ticket.

but… after this update, everything works.
So now, I hope the same.

Hi all, sharing another Matter-related fix for Homey SHS on Docker. This is a different issue from Pepe’s IPv6 routing fix (great post!), but equally frustrating. It took some digging but the fix is
permanent and clean.


Symptoms

  • Homey SHS runs on a NAS (UGREEN DXP2800) in Docker with network_mode: host
  • Matter daemon fails to initialize on startup
  • Homey logs show: ENDPOINT_POOL_FULL (0x00c1)
  • Other Homey features (Zigbee, Z-Wave, Wi-Fi devices) work fine
  • Restarting Homey sometimes fixes it temporarily, especially if you stop other containers first

Root cause

The Matter stack uses the CHIP SDK, which tries to bind a UDP socket on every host network interface at startup. There’s an internal limit of roughly 16–18 endpoints in the pool.

On a NAS running multiple Docker stacks, the host interface count explodes because:

  • Each Docker bridge network creates 1 host interface
  • Each bridge-connected container creates 1 veth pair (another host interface)
  • Add libvirt bridges, loopback, your physical NIC… it adds up fast

In my case I had 24 interfaces — well over the limit. The CHIP SDK ran out of endpoints trying to bind them all, and Matter never started.

How to check if this is your problem

SSH into your NAS and count interfaces:

ip link show | grep -c ‘[1]

If this number is above ~16, and you see ENDPOINT_POOL_FULL in your Homey logs, this is likely your issue.

You can also see what’s eating up interfaces:

Docker bridge networks (1 interface each)

docker network ls

veth pairs from bridge-connected containers

ip link show | grep veth

Solution: reduce host interfaces by consolidating Docker networks

The idea is simple: instead of each Docker Compose stack creating its own bridge network, make them all share a single one. Then use the sidecar pattern to group containers that can share a network
namespace (= 1 veth for the whole group instead of 1 per container).

High-level steps:

  1. Create one shared Docker network:
    docker network create --driver bridge shared
  2. Move all stacks to the shared network. In each docker-compose.yml, replace per-stack networking with:
    networks:
    shared:
    external: true
  3. And on each service:
    networks:
    • shared
  4. Group related containers as sidecars. If containers don’t need to talk to the outside world independently make one the “anchor” and attach the rest:

Homey Matter logs (should show clean init, no ENDPOINT_POOL_FULL)

docker logs homey-shs | grep -i matter

Important notes

  • The sidecar pattern means if the anchor container restarts, its sidecars temporarily lose network. They recover once the anchor is back.
  • All ports for a sidecar group must be declared on the anchor service.
  • Host-mode containers (like Homey SHS itself, Zigbee2MQTT, Mosquitto) don’t create veths — they’re already fine.
  • When adding new containers in the future, always use the shared network or sidecar pattern. Never let a stack create its own bridge network, or your interface count will creep back up.

Hope this helps someone else. The error message ENDPOINT_POOL_FULL is pretty opaque and there’s not much about it online in the context of Docker. Cheers!


  1. 0-9 ↩︎

I haven’t had these issues with SHS v13.0.0 in kubernetes. I installed it using this guide Homey Self Hosted Server in Kubernetes · GitHub.

It has an IP on my network using macvlan.

In the homey app. Open devices, add new device, matter, scan QR code.

This is my problem and I believe your fix will work, BUTT I tried to start with your Step 1 Ensure RA is enabled and got command not found.

Step 2 completely fries my brain and I don’t have a Mac to do this on either. So I guess I can’t find the next “hop”

This guide also helped me to setup matter over thread. Since I don’t have a Mac either, I’ve looked up the WIndows Powershell equivalent of the netstat command. I have found the IPv6 routing to my Google TV 4K, that acts as my Thread Border Router with this command:

Get-NetRoute -AddressFamily IPv6 | Where-Object { $_.DestinationPrefix -like "fd*" }

The result contains something like this:

DestinationPrefix : fd__:::1::/64
NextHop           : fe:::::
ifIndex           : 12

You can then paste this information in the script that @majorzoltanpepe proposed as boot-script:

/sbin/sysctl -w net.ipv6.conf.all.accept_ra=2
/sbin/sysctl -w net.ipv6.conf.default.accept_ra=2
/sbin/sysctl -w net.ipv6.conf.eth0.accept_ra=2

/sbin/ip -6 route add fd29:.../64 via fe80:... dev eth0 metric 50 2>/dev/null || true

So, if the rest of your network and TBR are setup correctly and you skip all trouble-shooting steps this is all you need: Run powershell script, paste results in boot-script and reboot your Synology NAS.

@majorzoltanpepe Thanks very much for the extensive guide!

For me adding an additional route also fixed it. First try it failed because I used the wrong address. I have multiple appliances that act as a border router in my network (Nets hub gen 2, Ikea Dirigera, Google TV streamer, Homey Pro 2023).

Some info that Copilot told me to keep (in Dutch)

Symptoom:

- Matter-over-Thread pairing op SHS faalt

- Werkt wel op Homey Pro

- Werkt wel via HomeyLink

Belangrijkste aanwijzing:

- avahi-browse ziet Matter devices op fd07:a96:830:1::/64

- ping6 gaf: “Network is unreachable”

Oorzaak:

- Synology kende geen route naar het Thread prefix

Oplossing:

- IPv6 route toegevoegd naar fd07:a96:830:1::/64

via het juiste fe80:: adres van Homey Pro

Resultaat:

- Matter-over-Thread pairing werkt op SHS

Matter-over-Thread timeout on Homey SHS / Synology with Google Nest Hub

I’m trying to pair an IKEA TIMMERFLOTE (Matter-over-Thread) with Homey Self-Hosted Server, but pairing consistently ends with:

Could not pair node (Matter code: TIMEOUT (0x0032))

My setup:

  • Homey SHS 13.3.1
  • Homey app 10.0.0.2028
  • Synology DS725+ / Container Manager
  • network_mode: host
  • Homey Bridge
  • TP-Link Archer AXE75
  • KPN native IPv6
  • Google Nest Hub 2nd generation as Thread Border Router
  • The TIMMERFLOTE is already working on the Google/Nest Thread network

I have done quite a bit of troubleshooting and have ruled out several potential issues.

IPv6 is working inside the Homey container. The container sees Global IPv6, ULA and link-local addresses on eth0:

2a02:a457:5d76:ff00:…/64
fd34:27c3:6391:5a72:…/64
fe80::…/64

Homey Matter also starts with:

net.ipv6.conf.eth0.disable_ipv6=0
net.ipv6.conf.eth0.accept_ra=2

The Matter service is listening on IPv6:

udp6 0 0 :::5540 :::* 18488/com.athom.mat

Using tcpdump on eth0, I can see IPv6 mDNS traffic to ff02::fb, including actual Matter traffic:

_matter._tcp.local

Homey also already has an existing Matter connection over IPv6:

Connection update: null → fe80::5e6a:41d8:f31d:e186%eth0

When trying to add the TIMMERFLOTE, the Homey log shows:

[Pairing] Start
Got status update: SEARCHING
Starting pairing with payload
Pairing to device…
Finished with error: Could not pair node (Matter code: TIMEOUT (0x0032))

What caught my attention is the IPv6 routing table on the Synology:

2a02:a457:5d76:ff00::/64 dev eth0
fd34:27c3:6391:5a72::/64 dev eth0
fe80::/64 dev eth0
default via fe80::42ae:30ff:feb6:10d8 dev eth0

There is no separate /64 route to the Thread mesh.

I’ve read in this topic that other Synology/SHS users with similar Matter-over-Thread timeouts managed to solve the issue by manually adding a route to the Thread prefix via the link-local IPv6 address of their Thread Border Router.

My question: has anyone managed to get this working specifically with a Google Nest Hub 2nd generation as the Thread Border Router?

If so, how can I determine the correct Thread /64 prefix and the link-local IPv6 next-hop address of the Google Nest Hub, so I can temporarily add the route to the Synology and test it?

I’d rather not add IPv6 routes blindly without first confirming the correct Thread prefix and next hop for the Google Thread network.

Hi, I kind of sorted it out for my (Synology DS 918+ based) based Homey SHS on Docker issue. My NAS is using latest version of the OS, but that’s using version 4.4.x of the Linux kernel. This version of the kernal has an issue in translating IPV6 RA’s (Route Advertisements) into entries in the routing table.

I fixed it first by adding a static route, but that’s not a really stable solution. Today I improved the solution by working with Copilot to create a script that listens for RA’s and creates route entries in the routing table based on the RA’s. It has been running for a few hours now and seems to do the job.

There can be more than one border router that is sending RA’s. That’s not a problem, because the route is registered for a certain prefix. My expectation is that it also will cover your scenario.

The following command (run it from an ssh shell) is important. It will listen for RA’s and show the details. It might provide you with the info you’re looking for.

sudo tcpdump -i ovs_eth0 -n -vv 'icmp6 and ip6[40] == 134'

Your network connector might have a different name though.

Thank you Bjorn, I will try this

It appears Google TV regularly changes the ULA prefix, so the fd... route in your routing table needs to be updated accordingly.

I’ve created a script that runs as a scheduled task on my Synology. It actively sends out a Router Solicitation (RS), which triggers all routers on the network to respond with a Router Advertisement (RA). The script filters the RA that contains the Thread network prefix and compares it with the currently installed route. Only if the prefix has changed, it updates the routing table. This way the Synology always has a valid route to the Thread mesh without any manual intervention.

#!/bin/bash
IFACE="eth0"

# Stuur Router Solicitation en vang de RA's op
RDISC_OUTPUT=$(/sbin/rdisc6 "$IFACE" 2>&1)

# Extraheer Thread-prefix (ULA, begint met fd)
NEW_PREFIX=$(echo "$RDISC_OUTPUT" | grep -Eo 'fd[0-9a-f:]+::/[0-9]+' | head -1)

# Extraheer TBR link-local adres (from-regel na de Thread-prefix)
TBR_LINK_LOCAL=$(echo "$RDISC_OUTPUT" | \
  grep -A4 "$NEW_PREFIX" | \
  grep "from" | \
  grep -Eo 'fe80::[0-9a-f:]+' | head -1)

# TBR niet gevonden — foutmelding en stop
if [ -z "$NEW_PREFIX" ] || [ -z "$TBR_LINK_LOCAL" ]; then
  echo "=== FOUT: Thread-prefix of TBR niet gevonden $(date) ==="
  echo "$RDISC_OUTPUT"
  exit 1
fi

# Haal huidige geïnstalleerde Thread-route op
CURRENT_PREFIX=$(ip -6 route show dev "$IFACE" | grep "^fd" | awk '{print $1}' | head -1)

# Geen wijziging — stilletjes stoppen, geen output, geen mail
if [ "$NEW_PREFIX" = "$CURRENT_PREFIX" ]; then
  exit 0
fi

# Prefix is gewijzigd of ontbreekt — bijwerken en rapporteren
echo "=== Thread route bijgewerkt $(date) ==="
echo "Oude prefix  : ${CURRENT_PREFIX:-'(geen)'}"
echo "Nieuwe prefix: $NEW_PREFIX"
echo "TBR          : $TBR_LINK_LOCAL"

# Verwijder oude Thread-routes
ip -6 route show dev "$IFACE" | grep "^fd" | awk '{print $1}' | \
  while read -r OLD; do
    ip -6 route del "$OLD" dev "$IFACE" 2>/dev/null
  done

# Voeg nieuwe route toe
ip -6 route add "$NEW_PREFIX" via "$TBR_LINK_LOCAL" \
  dev "$IFACE" metric 50 2>/dev/null || true

# Zet RA-acceptatie goed
/sbin/sysctl -w net.ipv6.conf.all.accept_ra=2 > /dev/null
/sbin/sysctl -w net.ipv6.conf.default.accept_ra=2 > /dev/null
/sbin/sysctl -w net.ipv6.conf.eth0.accept_ra=2 > /dev/null