You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found by an adversarial combined-tree audit of 9c9a1d8..269a6d4; survived two independent refuters and re-verified in 269a6d4.
Filing rather than fixing — the current behavior is deliberate and commented as such, so changing it is a design call, not a chore. See the design question at the bottom.
Where
crates/hytte-services/src/networkd.rs:340-345, inside the LinkBackend::Networkd arm:
ifletErr(e) = refresh(&links_writer,&primary_writer,&source_writer).await{
tracing::info!(error = ?e,"networkd unreachable at startup; service inert");return;}loop{matchlisten(&links_writer,&primary_writer,&source_writer).await{
...}
tokio::time::sleep(Duration::from_secs(2)).await;}
The return is before the retry loop. A single failed refresh at startup ends the task for the entire process lifetime. source stays LinkSource::Unknown, so the panel shows "No link manager has answered yet" forever and no retry ever happens — the 2 s retry loop below is unreachable from this path.
Why that's a bug and not just a policy
The surrounding comment justifies it:
isn't running on this host and no NM is present either — log once at info and stay inert rather than hammering dbus in a 2s retry loop for the rest of the process lifetime.
But this code is inside the LinkBackend::Networkd arm — reached only after the backend probe already determined networkd is the backend on this host. The "networkd isn't running here" case is LinkBackend::None, which is handled separately at :357-361 and correctly publishes LinkSource::Unavailable.
So the guard defends against a condition that the probe has already ruled out, while catching the condition it should tolerate: a transientrefresh failure microseconds after the probe's own call succeeded (networkd restarting, a D-Bus hiccup, ServiceUnknown during systemctl restart systemd-networkd). One unlucky moment at boot and the network panel is permanently wrong until the shell is restarted.
Note this is the same class as #613 (wifi backend selection not re-entrant, so a transient probe failure needs a restart to recover) — one layer over, in networkd rather than wifi_backend. #613 is currently held deliberately: #609's error! line exists to measure how often the transient failure fires, and shipping a retry destroys the measurement before it's taken. That reasoning applies to wifi_backend; whether it also applies here is the open question.
A related refuted claim, recorded so nobody re-files it: the audit also proposed that LinkSource::Unavailable is only reachable from a failed networkd read. Two independent refuters killed that on the source — Unavailable is published from the LinkBackend::None arm as a positive finding, as documented. That part is fine.
Severity
Medium. Narrow trigger (a failure in a window of microseconds), but the consequence is total and silent for the rest of the session: the link panel is stuck on an indeterminate state with no recovery short of restarting the shell.
Two defensible shapes, and I don't want to pick unilaterally:
Retry here too — move the refresh failure into the loop so it retries every 2 s like listen already does. Simple, symmetric with listen's existing behavior, and the "don't hammer dbus" worry is largely moot because the probe already told us networkd is present. Risk: on a pathological host we do poll a dead service every 2 s forever.
I lean (2): it fixes the transient case, keeps a ceiling on D-Bus traffic, and — like #609's error! line — leaves evidence in the log that this path fired, which is what would let us close #613 on data rather than guesswork. Happy to build either.
Found by an adversarial combined-tree audit of
9c9a1d8..269a6d4; survived two independent refuters and re-verified in269a6d4.Filing rather than fixing — the current behavior is deliberate and commented as such, so changing it is a design call, not a chore. See the design question at the bottom.
Where
crates/hytte-services/src/networkd.rs:340-345, inside theLinkBackend::Networkdarm:The
returnis before the retry loop. A single failedrefreshat startup ends the task for the entire process lifetime.sourcestaysLinkSource::Unknown, so the panel shows "No link manager has answered yet" forever and no retry ever happens — the 2 s retry loop below is unreachable from this path.Why that's a bug and not just a policy
The surrounding comment justifies it:
But this code is inside the
LinkBackend::Networkdarm — reached only after the backend probe already determined networkd is the backend on this host. The "networkd isn't running here" case isLinkBackend::None, which is handled separately at:357-361and correctly publishesLinkSource::Unavailable.So the guard defends against a condition that the probe has already ruled out, while catching the condition it should tolerate: a transient
refreshfailure microseconds after the probe's own call succeeded (networkd restarting, a D-Bus hiccup,ServiceUnknownduringsystemctl restart systemd-networkd). One unlucky moment at boot and the network panel is permanently wrong until the shell is restarted.Note this is the same class as #613 (wifi backend selection not re-entrant, so a transient probe failure needs a restart to recover) — one layer over, in networkd rather than
wifi_backend. #613 is currently held deliberately: #609'serror!line exists to measure how often the transient failure fires, and shipping a retry destroys the measurement before it's taken. That reasoning applies towifi_backend; whether it also applies here is the open question.A related refuted claim, recorded so nobody re-files it: the audit also proposed that
LinkSource::Unavailableis only reachable from a failed networkd read. Two independent refuters killed that on the source —Unavailableis published from theLinkBackend::Nonearm as a positive finding, as documented. That part is fine.Severity
Medium. Narrow trigger (a failure in a window of microseconds), but the consequence is total and silent for the rest of the session: the link panel is stuck on an indeterminate state with no recovery short of restarting the shell.
Design question for @annikahannig
Two defensible shapes, and I don't want to pick unilaterally:
refreshfailure into the loop so it retries every 2 s likelistenalready does. Simple, symmetric withlisten's existing behavior, and the "don't hammer dbus" worry is largely moot because the probe already told us networkd is present. Risk: on a pathological host we do poll a dead service every 2 s forever.error!(notinfo!) so the give-up is visible injournalctl, matching the pattern fix(wifi): a failed backend probe is no longer indistinguishable from "no backend" (#607) #609 established for an inconclusive probe.I lean (2): it fixes the transient case, keeps a ceiling on D-Bus traffic, and — like #609's
error!line — leaves evidence in the log that this path fired, which is what would let us close #613 on data rather than guesswork. Happy to build either.Refs #608, #609, #610, #613.