Skip to content

Device with a "nic" child relationship gets an endless one-directional Connected/Disconnected event stream instead of tracking its own real presence #1736

Description

@mormegil6

What installation are you running?

Production (netalertx) 📦

Is there an existing issue for this?

The issue occurs in the following browsers. Select at least 2.

  • Firefox
  • Chrome
  • Edge
  • Safari (unsupported) - PRs welcome
  • N/A - This is an issue with the backend

Current Behavior

Once a device has at least one other device linked to it via devParentRelType='nic' (the Host/NIC relationship, meant for tracking a host's multiple network interfaces as one logical device), the parent's own directly-detected network presence stops being used at all. Instead, every scan cycle, the parent's Connected/Disconnected events lock onto whatever the nic child's presence is - and because of how this interacts with event generation, only ONE of the two event types can ever fire for that parent, forever, regardless of what's actually happening on the network. If the nic child is permanently or persistently unreachable, the parent gets an endless stream of Connected events and zero Disconnected events, even while the parent's own real network presence is being genuinely, repeatedly re-detected every cycle. (The mirror case - a permanently-reachable nic child - produces the opposite: endless Disconnected, never Connected, even if the parent is actually offline.)

This surfaced as a real-world notification flood: a device running NetAlertX itself started reporting itself as endlessly "Disconnected."

Expected Behavior

A parent device's own directly-detected presence should never be completely discarded. At minimum, the nic child's presence should only be able to bring the parent's presence UP (mark it present when its own detection missed it), never force it down when the parent itself was just detected as genuinely present - and the reverse for the "require all NICs online" mode. A device that answers a scan directly should never be permanently reported as either connected-only or disconnected-only regardless of its own real state.

Steps To Reproduce

Reproduced in an isolated Docker container (ghcr.io/jokob-sk/netalertx:latest, same image as production), separate from any production data, over a real ~2 hour window of live scan cycles (not simulated/manually invoked - this is the shipped scheduler running the shipped code).

  1. Fresh NetAlertX instance. LOG_LEVEL='trace', TIMEZONE='Europe/Warsaw', ARPSCAN_RUN_SCHD='*/2 * * * *'.
  2. Create two devices:
    • A device with genuine, continuously-renewed real presence. (In my repro this was the container's own self-detected interface, auto-registered every cycle via save_own_device()/devSourcePlugin='local_MAC' independent of ARPSCAN - any device with reliably real, continuous presence works the same way. MAC in this run: 0a:17:f2:8d:02:97.)
    • A second device, devParentMAC pointing at the first, devParentRelType='nic'. This one should never actually be reachable on the network (MAC in this run: bb:bb:bb:bb:bb:02, a fictitious MAC that never answers ARP).
  3. Let several real scan cycles pass (6+ recommended for a clear pattern).
  4. Query Events for the parent MAC.

Result: the parent gets a Connected event every single cycle, and never a Disconnected event, for as long as the nic child stays unreachable - even though the parent's own devLastConnection keeps genuinely advancing every cycle (proof its real presence IS being detected correctly underneath the bug).

Note on constructing a minimal repro: a device that is never real on the wire at all (no genuine detection, ever) gets zero events of any kind, not a one-sided stream - this is a separate, structural gate in insert_events() (the "New Connections" branch requires the MAC to actually be a row in CurrentScan), not part of this bug. The flood specifically requires a parent with real, ongoing detection whose presence then gets discarded by a fake/absent nic child - i.e. genuine detection silently overridden, not "device that was never really there."

Relevant app.conf settings

LOG_LEVEL='trace'
TIMEZONE='Europe/Warsaw'
ARPSCAN_RUN_SCHD='*/2 * * * *'
SCAN_SUBNETS='172.17.0.0/28 --interface=eth0'

docker-compose.yml

services:
  netalertx:
    image: ghcr.io/jokob-sk/netalertx:latest
    container_name: netalertx-repro-nic2
    cap_add:
      - CHOWN
      - NET_ADMIN
      - NET_BIND_SERVICE
      - NET_RAW
      - SETGID
      - SETUID
    ports:
      - "11041:1031"
      - "10412:20212"
    environment:
      TZ: Europe/Warsaw
      PORT: 1031
      GRAPHQL_PORT: 20212
    volumes:
      - ./data:/data

(Isolated repro setup - bridge networking rather than production's `network_mode: host`, so it doesn't collide with a real instance on the same box. `cap_add` is required for the image's entrypoint to start at all under bridge networking - without it, several bundled binaries with Linux file-capabilities fail with "Operation not permitted", exit 126, unrelated to this bug.)

Debug or Trace enabled

  • I have read and followed the steps in the wiki link above and provided the required debug logs and the log section covers the time when the issue occurs.

Relevant app.log section

[Process Scan]  Processing scan results
[Process Scan]  Exclude ignored devices
[Process Scan] Print Stats
    {'devMac': '0a:17:f2:8d:02:97', 'devName': 'ReproParent-selfMAC', ..., 'devLastConnection': '2026-08-13 04:10:34', ..., 'devPresentLastScan': 0, ...}
[Process Scan] Stats end
[Process Scan] Sessions Events (connect / disconnect)
[Process Scan] Creating new devices
[Process Scan] Updating Devices Info
[Process Scan] Updating Sync Hub Node
[Process Scan] Updating devLastConnection from CurrentScan
[Process Scan] Updating Presence from CurrentScan
[Process Scan] Updating NICs presence
[Process Scan] Updating forced presence
...
[Process Scan] Pairing session events (connection / disconnection)
[Process Scan] Creating sessions snapshot
[Process Scan] Inserting scan results into Online_History

This is one full cycle: notice devPresentLastScan: 0 in the "Print Stats" dump taken before this cycle's own presence update runs - i.e. this is the value left over from last cycle's "Updating NICs presence" step - while devLastConnection from the previous cycle is already fresh (one cycle old), proving the device really was detected as present a moment earlier. The step order confirms the mechanism: "Updating Presence from CurrentScan" (which would correctly set this to 1) runs, then "Updating NICs presence" immediately overwrites it back down.

This section is trimmed to the log lines that demonstrate the mechanism directly. A curated excerpt of one complete cycle end-to-end is attached here: trace_excerpt_one_full_cycle_06-12-41.log. The complete internal application log for this run (8MB, LOG_LEVEL=trace) is attached here: app_trace_log_full.log.

Docker Logs

[Notification] final_json: {"new_devices": [], ..., "events": [{"devName": "ReproParent-selfMAC", "eveMac": "0a:17:f2:8d:02:97", "devVendor": "", "eveIp": "172.17.0.2", "eveDateTime": "2026-08-13T06:10:34+02:00", "eveEventType": "Connected", ...}], "events_meta": {...}, ...}

This is the application's own generated notification payload - proof this isn't just an internal DB inconsistency, it's what NetAlertX itself reports as a real "Connected" event to the user, repeatedly, cycle after cycle, for a device whose actual state never changes.

Supporting data (SQL run directly against the repro instance's own app.db):

SELECT eveDateTime, eveMac, eveEventType FROM Events WHERE eveMac='0a:17:f2:8d:02:97' ORDER BY eveDateTime;
2026-08-12 22:35:09  0a:17:f2:8d:02:97  Connected   (New Device, first seen)
2026-08-13 04:01:11  0a:17:f2:8d:02:97  Connected
2026-08-13 04:03:11  0a:17:f2:8d:02:97  Connected
2026-08-13 04:05:18  0a:17:f2:8d:02:97  Connected
2026-08-13 04:06:21  0a:17:f2:8d:02:97  Connected
2026-08-13 04:08:27  0a:17:f2:8d:02:97  Connected
2026-08-13 04:10:34  0a:17:f2:8d:02:97  Connected
2026-08-13 04:12:41  0a:17:f2:8d:02:97  Connected

8 Connected, 0 Disconnected, across ~11 minutes of accumulated real cycles (plus a long idle gap in between where the container was simply left running). Negative control confirming the "never-real device" distinction noted above: the originally-planned fully-fictitious parent MAC (bb:bb:bb:bb:bb:01, never given a path into CurrentScan) produced exactly 0 events of any kind over the same ~7.5 hour window.

Full docker logs output (this run's complete history) is attached here: docker_logs_full.txt.

Metadata

Metadata

Labels

bug 🐛Something isn't workingnext release/in dev image 🚀This is coming in the next release or was already released if the issue is Closed.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions