Don't let a pyatv error during start up kill the child bridge - #1405
Merged
maxileith merged 1 commit intoJul 28, 2026
Merged
Conversation
validationLoop discarded three promises with `void`: credentialsValid(), startUp() and pairingRequired(). All three talk to the device through pyatv, so one transient error became an unhandled rejection and took the child bridge process down with it. Once Homebridge exhausts its four restart attempts the accessory stays gone until Homebridge is restarted by hand. Keep hold of the chain and attach a catch that logs the failure and retries the whole validation loop after a delay, addressing the two FIXMEs that were already sitting on those calls.
maxileith
approved these changes
Jul 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Any error raised while an accessory is starting up takes the whole child bridge down. From my log:
Homebridge only retries four times, so a device that is unreachable or misbehaving for a couple of
minutes leaves the accessory gone until Homebridge is restarted by hand.
Cause
validationLoopin the accessory constructor discards three promises withvoid:All three talk to the device through pyatv, and
startUp()in particular does a lot of it(
getPowerState,getDeviceState,getMediaType,createVolumeFan->getState,listApps).voidthrows the promise away along with its rejection, so nothing is left holding it; on Node 18+an unhandled rejection terminates the process by default, which is the
code 1above. The twoFIXME: catch errors / remove voidcomments already mark this.Change
Keep hold of the chain and attach a
catchthat logs the failure and retries the whole validationloop after a delay, rather than letting the rejection escape. Both FIXMEs are addressed; the happy
path is unchanged.
Testing
npm run buildpasses (lint at--max-warnings=0+ tsc). Running on a Raspberry Pi with three AppleTVs; bridge starts normally and the accessories behave as before. The retry path itself only triggers
on a pyatv failure, so it is exercised by the fault rather than by the happy path.
Note
The NaN error that led me here is a pyatv bug and I have a fix open for it separately
(postlund/pyatv#2897). This change is independent of that one: it is about any pyatv error during
start up being fatal to the child bridge rather than recoverable.