get_config() fetches GET /api/core/backup/download/this through _get(), which returns response.json(). That endpoint answers with config.xml itself (application/octet-stream), so .json() raises JSONDecodeError on every call. The except Exception around it logs a warning and returns running = "".
So get_config() has never returned a configuration from a real device since the initial commit. The unit tests did not catch it because they replace _get with a lambda that returns an XML string, which skips the real .json() call.
Verified live (read-only, gw behind 172.22.8.50, 2026-10-11): status 200, content-type application/octet-stream, 505 755 bytes, body starts with <?xml, .json() → JSONDecodeError.
Fix: add _get_text() that returns response.text, and use it in get_config. A failed read now raises instead of returning an empty string, so netOrk can show the real reason (e.g. a 403 from an API key without the backup privilege) instead of "the device returned an empty configuration". The only caller is netOrk's poll (_collect_config), which already turns an exception into config_read = failed with the error text.
netOrk side: NetOrk/netork — config backup warning on every OPNsense device.
`get_config()` fetches `GET /api/core/backup/download/this` through `_get()`, which returns `response.json()`. That endpoint answers with `config.xml` itself (`application/octet-stream`), so `.json()` raises `JSONDecodeError` on every call. The `except Exception` around it logs a warning and returns `running = ""`.
So `get_config()` has never returned a configuration from a real device since the initial commit. The unit tests did not catch it because they replace `_get` with a lambda that returns an XML string, which skips the real `.json()` call.
**Verified live** (read-only, `gw` behind 172.22.8.50, 2026-10-11): status 200, content-type `application/octet-stream`, 505 755 bytes, body starts with `<?xml`, `.json()` → `JSONDecodeError`.
**Fix:** add `_get_text()` that returns `response.text`, and use it in `get_config`. A failed read now raises instead of returning an empty string, so netOrk can show the real reason (e.g. a 403 from an API key without the backup privilege) instead of "the device returned an empty configuration". The only caller is netOrk's poll (`_collect_config`), which already turns an exception into `config_read = failed` with the error text.
netOrk side: NetOrk/netork — config backup warning on every OPNsense device.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
get_config()fetchesGET /api/core/backup/download/thisthrough_get(), which returnsresponse.json(). That endpoint answers withconfig.xmlitself (application/octet-stream), so.json()raisesJSONDecodeErroron every call. Theexcept Exceptionaround it logs a warning and returnsrunning = "".So
get_config()has never returned a configuration from a real device since the initial commit. The unit tests did not catch it because they replace_getwith a lambda that returns an XML string, which skips the real.json()call.Verified live (read-only,
gwbehind 172.22.8.50, 2026-10-11): status 200, content-typeapplication/octet-stream, 505 755 bytes, body starts with<?xml,.json()→JSONDecodeError.Fix: add
_get_text()that returnsresponse.text, and use it inget_config. A failed read now raises instead of returning an empty string, so netOrk can show the real reason (e.g. a 403 from an API key without the backup privilege) instead of "the device returned an empty configuration". The only caller is netOrk's poll (_collect_config), which already turns an exception intoconfig_read = failedwith the error text.netOrk side: NetOrk/netork — config backup warning on every OPNsense device.