Skip to content

Deleting a device referenced as devParentMAC / NEWDEV_devParentMAC breaks the entire Devices table with an uncaught atob() error (infinite loading spinner) #1758

Description

@tobi44

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

What installation are you running?
Production (netalertx), version v25.8.6 (Docker, jokobsk/netalertx)

Browsers affected: Chrome (confirmed). Likely all browsers, since it's a plain JS/DataTables issue, not browser-specific.

Current Behavior

After deleting a device that was used as a network Parent Node (either as Settings → New Devices → Parent Node default, or as another device's individual Parent Node), the entire "My Devices" table becomes permanently stuck on the loading spinner ("Laden ..." / "Processing..."). No devices are shown, and the page never recovers — a hard reload does not help.

The backend is completely healthy during this: all AJAX/GraphQL requests (devices.php, query_graphql.php, devices_filters.php, tile_cards.php, etc.) complete successfully and quickly (100–200ms). The failure is purely client-side.

Browser console shows:

Uncaught InvalidCharacterError: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
at renderDeviceLink (ui_components.js:816:37)
at k.fn.init.createdCell (devices.php:1675:28)
at Ha (jquery.dataTables.min.js:25:167)
at O (jquery.dataTables.min.js:16:421)
at wb (jquery.dataTables.min.js:40:32)
at jquery.dataTables.min.js:37:167
at i (jquery.dataTables.min.js:35:338)
at Object.success (jquery.dataTables.min.js:36:40)
at c (jquery.min.js:2:27742)
at Object.fireWith [as resolveWith] (jquery.min.js:2:28487)
Root cause
Settings → New Devices → Parent Node (NEWDEV_devParentMAC) stores a MAC address that is assigned as the default devParentMAC for every newly discovered device.
If the device with that MAC is later deleted (e.g. via the built-in delete_dev custom property action), NEWDEV_devParentMAC keeps pointing to a MAC that no longer exists in the Devices table. Likewise, every device that already inherited this MAC as devParentMAC keeps a now-dangling reference.
server/scan/device_handling.py (around line 110–119) only re-assigns devParentMAC for devices where it is currently NULL, "", "null", "(unknown)" or "(Unknown)" — a device with a stale but well-formed MAC in devParentMAC is never corrected automatically, because it's not considered "empty" by that check.
In front/devices.php, the "Parent Mac" column definition (columnDefs, createdCell) only validates the format of devParentMAC via isValidMac() (common.js, checkMacOrInternet()), which returns true for any string matching the MAC regex or the literal "internet" — it does not check whether the referenced device actually exists:
js
// front/devices.php (~line 897)
if (!isValidMac(cellData)) {
$(td).html('');
return;
}
const data = { id: cellData, text: cellData };
...
const chipHtml = renderDeviceLink(data, spanWrap, true);
renderDeviceLink() then calls getDevDataByMac(data.id) (common.js:1009), which — if no device matches — returns the string "Unknown" (not undefined/null):
js
// common.js:1033
return "Unknown"; // Return a default value if MAC address is not found
Back in renderDeviceLink() (ui_components.js:816):
js
${atob(device.devIcon)}

Since device is now the string "Unknown", device.devIcon is undefined. atob(undefined) is coerced to atob("undefined"), which is not valid Base64 (odd length / invalid padding), throwing an uncaught InvalidCharacterError.

Because this happens inside DataTables' createdCell callback during row rendering, the exception is uncaught and aborts the rest of the table rendering entirely — including whatever code is supposed to hide the loading spinner. Every row whose devParentMAC points to the deleted device triggers this, so in practice the whole devices list becomes permanently stuck as soon as one dangling parent reference exists.
Steps to Reproduce
Have at least one non-trivial network with several devices sharing a common Parent Node (either via NEWDEV_devParentMAC default, or individually set).
Delete the device that is set as that Parent Node (e.g. via the device's "Delete device" custom property action).
Reload the Devices page (devices.php#my_devices).
Observe: the page gets stuck on "Laden ..." / "Processing..." indefinitely; console shows the atob InvalidCharacterError above.

Workaround

Manually clear the dangling references in the database:

sql
UPDATE Settings SET setValue = '' WHERE setKey = 'NEWDEV_devParentMAC';
UPDATE Devices SET devParentMAC = '' WHERE devParentMAC = '';

After this, devParentMAC is empty for the affected devices, isValidMac('') returns false, the "Parent Mac" column renderer skips the renderDeviceLink() call entirely, and the page loads normally again.

Suggested fix locations
front/js/common.js — getDevDataByMac(): return null instead of the string "Unknown" when no match is found.
front/js/ui_components.js — renderDeviceLink(): guard against a falsy/invalid device (and against device.devIcon being empty/undefined) before calling atob().
front/devices.php — "Parent Mac" createdCell: validate that the referenced device actually exists in the cached device list, not just that the string looks like a MAC.
server/scan/device_handling.py (~line 110–119): consider also re-resolving devParentMAC values that point to a MAC no longer present in Devices, not just empty/placeholder values.

Expected Behavior

  • Deleting a device should either be blocked/warned against if it's referenced as a Parent Node by other devices or by NEWDEV_devParentMAC, or should automatically clear those dangling references.

  • At minimum, the frontend should not crash on a dangling devParentMAC reference. getDevDataByMac() returning the string "Unknown" instead of null/undefined is fragile and should be fixed, and renderDeviceLink() should guard against device not being a proper object before calling atob() on device.devIcon.

  • A single bad/stale reference in one row should never be able to abort rendering of the entire table for all rows.

Steps To Reproduce

Load the site

Relevant app.conf settings

docker-compose.yml

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

  PASTE LOG HERE. Using the triple backticks preserves format.

Docker Logs

  PASTE DOCKER LOG HERE. Using the triple backticks preserves format.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Waiting for reply⏳Waiting for the original poster to respond, or discussion in progress.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