From 41fa1f4a2c048302dbdbe22cdd8c1374d703e448 Mon Sep 17 00:00:00 2001 From: Steven Pritchard Date: Fri, 4 Sep 2026 14:28:07 +0000 Subject: [PATCH] Do not swallow RunTimeoutError while collecting facts `Puppet::Agent::RunTimeoutError` inherits from `Exception` so that it escapes the usual `rescue StandardError` handlers and aborts the run. The fact handler, however, rescues `Exception` and only re-raises SystemExit and NoMemoryError, so a run timeout that fires during fact collection was wrapped into a plain Puppet::Error ("Could not retrieve local facts: execution expired") and the run carried on to send a report as if nothing had happened. Re-raise RunTimeoutError alongside SystemExit and NoMemoryError so the agent aborts the run as intended. Fixes part of #485 Co-Authored-By: Claude Fable 5.1 Signed-off-by: Steven Pritchard --- lib/puppet/configurer/fact_handler.rb | 6 +++++- spec/unit/configurer/fact_handler_spec.rb | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/puppet/configurer/fact_handler.rb b/lib/puppet/configurer/fact_handler.rb index 64f8fb9da9..1cf01fb69f 100644 --- a/lib/puppet/configurer/fact_handler.rb +++ b/lib/puppet/configurer/fact_handler.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require_relative '../../puppet/agent' require_relative '../../puppet/indirector/facts/facter' require_relative '../../puppet/configurer' @@ -20,7 +21,10 @@ def find_facts facts.name = Puppet[:node_name_value] end facts - rescue SystemExit, NoMemoryError + rescue SystemExit, NoMemoryError, Puppet::Agent::RunTimeoutError + # RunTimeoutError means the agent run as a whole has exceeded `runtimeout`. + # Let it propagate so the run is aborted instead of wrapping it in a + # Puppet::Error and carrying on with the rest of the run. raise rescue Exception => detail message = _("Could not retrieve local facts: %{detail}") % { detail: detail } diff --git a/spec/unit/configurer/fact_handler_spec.rb b/spec/unit/configurer/fact_handler_spec.rb index 1acf49c30a..16dc932b8b 100644 --- a/spec/unit/configurer/fact_handler_spec.rb +++ b/spec/unit/configurer/fact_handler_spec.rb @@ -58,6 +58,13 @@ def reload_facter expect { facthandler.find_facts }.to raise_error(Puppet::Error, /Could not retrieve local facts/) end + it "should re-raise RunTimeoutError so the agent run is aborted" do + expect(Puppet::Node::Facts.indirection).to receive(:find).and_raise(Puppet::Agent::RunTimeoutError, 'execution expired') + expect(Puppet).not_to receive(:log_exception) + + expect { facthandler.find_facts }.to raise_error(Puppet::Agent::RunTimeoutError, 'execution expired') + end + it "should only load fact plugins once" do expect(Puppet::Node::Facts.indirection).to receive(:find).once facthandler.find_facts