From d89f080becd316ed69ce5be4bf53e2e9d7a49d48 Mon Sep 17 00:00:00 2001 From: Jay Collett <486430+jaycollett@users.noreply.github.com> Date: Thu, 29 Jan 2026 13:09:19 -0500 Subject: [PATCH 1/2] Fix Proxmox livestats 500 error with null handling The livestats() method would crash with a 500 error when: - API calls returned null (connection failures, permission issues) - Node status/VM/container data was missing expected properties - Division by zero when no valid nodes were found Changes: - Add null check in apiCall() before calling getBody() - Check nodeData for null before array_map() - Add null checks for node_status, vm_stats, and container_stats - Track valid_nodes count to prevent division by zero - Use null coalescing for optional properties (cpu, memory) - Return "inactive" status gracefully instead of crashing Fixes linuxserver/Heimdall#1533 --- Proxmox/Proxmox.php | 64 ++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/Proxmox/Proxmox.php b/Proxmox/Proxmox.php index 408d1a3d20..72e248c32b 100644 --- a/Proxmox/Proxmox.php +++ b/Proxmox/Proxmox.php @@ -39,14 +39,21 @@ public function test() public function livestats() { $status = "active"; - $attrs = $this->getRequestAttrs(); $nodes = explode(",", $this->getConfigValue("nodes", "")); if ($nodes == [""]) { + $nodeData = $this->apiCall("nodes"); + if ($nodeData === null) { + return parent::getLiveStats("inactive", []); + } $nodes = array_map(function ($v) { return $v->node; - }, $this->apiCall("nodes")); + }, $nodeData); + } + + if (empty($nodes)) { + return parent::getLiveStats("inactive", []); } $vm_running = 0; @@ -56,39 +63,49 @@ public function livestats() $cpu_percent_sum = 0.0; $memory_total = 0.0; $memory_used = 0.0; + $valid_nodes = 0; + foreach ($nodes as $node) { $node_status = $this->apiCall("nodes/" . $node . "/status"); - $cpu_percent_sum += $node_status->cpu; - $memory_used += $node_status->memory->used; - $memory_total += $node_status->memory->total; + if ($node_status !== null) { + $valid_nodes++; + $cpu_percent_sum += $node_status->cpu ?? 0; + $memory_used += isset($node_status->memory) ? ($node_status->memory->used ?? 0) : 0; + $memory_total += isset($node_status->memory) ? ($node_status->memory->total ?? 0) : 0; + } $vm_stats = $this->apiCall("nodes/" . $node . "/qemu"); - $vm_total += count($vm_stats); - $vm_running += count( - array_filter($vm_stats, function ($v) { - return $v->status == "running"; - }) - ); + if ($vm_stats !== null) { + $vm_total += count($vm_stats); + $vm_running += count( + array_filter($vm_stats, function ($v) { + return isset($v->status) && $v->status == "running"; + }) + ); + } $container_stats = $this->apiCall("nodes/" . $node . "/lxc"); - $container_total += count($container_stats); - $container_running += count( - array_filter($container_stats, function ($v) { - return $v->status == "running"; - }) - ); + if ($container_stats !== null) { + $container_total += count($container_stats); + $container_running += count( + array_filter($container_stats, function ($v) { + return isset($v->status) && $v->status == "running"; + }) + ); + } } - $res = parent::execute($this->url("version"), $attrs); - $details = json_decode($res->getBody())->data; + if ($valid_nodes === 0) { + return parent::getLiveStats("inactive", []); + } $data = [ "vm_running" => $vm_running, "vm_total" => $vm_total, "container_running" => $container_running, "container_total" => $container_total, - "cpu_percent" => ($cpu_percent_sum / count($nodes)) * 100, - "memory_percent" => (100 / $memory_total) * $memory_used, + "cpu_percent" => ($cpu_percent_sum / $valid_nodes) * 100, + "memory_percent" => $memory_total > 0 ? (100 / $memory_total) * $memory_used : 0, ]; return parent::getLiveStats($status, $data); } @@ -107,6 +124,11 @@ public function url($endpoint) public function apiCall($endpoint) { $res = parent::execute($this->url($endpoint), $this->getRequestAttrs()); + + if ($res === null) { + return null; + } + $object = json_decode($res->getBody()); if (!$object instanceof \stdClass) { From e7fcd04e228ca55fbd0afbcae6d9313811ccead9 Mon Sep 17 00:00:00 2001 From: Jay Collett <486430+jaycollett@users.noreply.github.com> Date: Thu, 29 Jan 2026 13:40:39 -0500 Subject: [PATCH 2/2] Fix inactive status passing empty array to view template The livestats.blade.php view requires variables like $vm_running, $cpu_percent, etc. When returning "inactive" status, we were passing an empty array which caused undefined variable errors. Now passing $inactiveData with default zero values so the view renders properly even when the API is unreachable or returns no data. --- Proxmox/Proxmox.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Proxmox/Proxmox.php b/Proxmox/Proxmox.php index 72e248c32b..68d54d49d7 100644 --- a/Proxmox/Proxmox.php +++ b/Proxmox/Proxmox.php @@ -40,12 +40,22 @@ public function livestats() { $status = "active"; + // Default data for inactive status (view template requires these variables) + $inactiveData = [ + "vm_running" => 0, + "vm_total" => 0, + "container_running" => 0, + "container_total" => 0, + "cpu_percent" => 0, + "memory_percent" => 0, + ]; + $nodes = explode(",", $this->getConfigValue("nodes", "")); if ($nodes == [""]) { $nodeData = $this->apiCall("nodes"); if ($nodeData === null) { - return parent::getLiveStats("inactive", []); + return parent::getLiveStats("inactive", $inactiveData); } $nodes = array_map(function ($v) { return $v->node; @@ -53,7 +63,7 @@ public function livestats() } if (empty($nodes)) { - return parent::getLiveStats("inactive", []); + return parent::getLiveStats("inactive", $inactiveData); } $vm_running = 0; @@ -96,7 +106,7 @@ public function livestats() } if ($valid_nodes === 0) { - return parent::getLiveStats("inactive", []); + return parent::getLiveStats("inactive", $inactiveData); } $data = [