From 75c0b1bfc9c5f737d94a136a5b329d6a8285b122 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:51:27 +0100 Subject: [PATCH] fix(error-handler): prevent silent() from re-enabling error handling during recovery Root cause: silent() (core.func) unconditionally calls set -Eeuo pipefail and trap 'error_handler' ERR after every command. When build_container() intentionally disables error handling for its recovery section, any intermediate call through silent()/ re-enables it. This causes the grep/sed pipeline for missing_cmd extraction to trigger error_handler (grep returns exit code 1 on no match + pipefail = fatal). Fixes: 1. silent(): Save errexit state before disabling, only restore if it was active. Callers that intentionally disabled error handling (e.g. build_container recovery) are no longer silently re-enabled. 2. build.func: Add || true to missing_cmd grep pipeline as defense-in-depth against pipeline failure propagation. 3. build.func: Add explicit set +Eeuo pipefail / trap - ERR after post_update_to_api() call, before error classification grep/sed section. 4. build.func: Remove stale global combined_log variable from variables() that used a different path format (/tmp/install-SESSION-combined.log) than the actual local variable (/tmp/NSAPP-CTID-SESSION.log). The global was never written to and caused confusion when error_handler displayed it. --- misc/build.func | 12 ++++++++++-- misc/core.func | 15 +++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/misc/build.func b/misc/build.func index 8ee1903cd..b4f962e1b 100644 --- a/misc/build.func +++ b/misc/build.func @@ -48,7 +48,8 @@ variables() { EXECUTION_ID="${RANDOM_UUID}" # Unique execution ID for telemetry record identification (unique-indexed in PocketBase) SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" # Host-side container creation log - combined_log="/tmp/install-${SESSION_ID}-combined.log" # Combined log (build + install) for failed installations + # NOTE: combined_log is constructed locally in build_container() and ensure_log_on_host() + # as "/tmp/${NSAPP}-${CTID}-${SESSION_ID}.log" (requires CTID, not available here) CTTYPE="${CTTYPE:-${CT_TYPE:-1}}" # Parse dev_mode early @@ -4174,6 +4175,13 @@ EOF' # Report failure to telemetry API (now with log available on host) post_update_to_api "failed" "$install_exit_code" + # Defense-in-depth: Ensure error handling stays disabled during recovery. + # Some functions (e.g. silent/$STD) unconditionally re-enable set -Eeuo pipefail + # and trap 'error_handler' ERR. If any code path above called such a function, + # the grep/sed pipelines below would trigger error_handler on non-match (exit 1). + set +Eeuo pipefail + trap - ERR + # Show combined log location if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then msg_custom "📋" "${YW}" "Installation log: ${combined_log}" @@ -4287,7 +4295,7 @@ EOF' if [[ "$is_cmd_not_found" == true ]]; then local missing_cmd="" if [[ -f "$combined_log" ]]; then - missing_cmd=$(grep -oiE '[a-zA-Z0-9_.-]+: command not found' "$combined_log" | tail -1 | sed 's/: command not found//') + missing_cmd=$(grep -oiE '[a-zA-Z0-9_.-]+: command not found' "$combined_log" 2>/dev/null | tail -1 | sed 's/: command not found//') || true fi if [[ -n "$missing_cmd" ]]; then echo -e "${TAB}${INFO} Missing command: ${GN}${missing_cmd}${CL}" diff --git a/misc/core.func b/misc/core.func index c0460c0ff..0d203a77b 100644 --- a/misc/core.func +++ b/misc/core.func @@ -490,6 +490,8 @@ log_section() { # - Executes command with output redirected to active log file # - On error: displays last 20 lines of log and exits with original exit code # - Temporarily disables error trap to capture exit code correctly +# - Saves and restores previous error handling state (so callers that +# intentionally disabled error handling aren't silently re-enabled) # - Sources explain_exit_code() for detailed error messages # ------------------------------------------------------------------------------ silent() { @@ -507,14 +509,23 @@ silent() { return 0 fi + # Save current error handling state before disabling + # This prevents re-enabling error handling when the caller intentionally + # disabled it (e.g. build_container recovery section) + local _restore_errexit=false + [[ "$-" == *e* ]] && _restore_errexit=true + set +Eeuo pipefail trap - ERR "$@" >>"$logfile" 2>&1 local rc=$? - set -Eeuo pipefail - trap 'error_handler' ERR + # Restore error handling ONLY if it was active before this call + if $_restore_errexit; then + set -Eeuo pipefail + trap 'error_handler' ERR + fi if [[ $rc -ne 0 ]]; then # Source explain_exit_code if needed