-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
[core]: error_handler.func
Comprehensive error handling and signal management module providing exit code explanations, error handlers with logging, and signal trap configuration for all Community-Scripts projects.
- Overview
- Exit Code Reference
- Error Handler Functions
- Signal Traps
- Initialization & Setup
- Error Logging
- Best Practices
- Debugging
- Contributing
The error_handler.func module provides robust error handling infrastructure:
- ✅ Comprehensive exit code mapping (1-255+ codes documented)
- ✅ Detailed error messages with line numbers and commands
- ✅ Signal trap configuration (ERR, EXIT, INT, TERM, RETURN)
- ✅ Error logging to persistent files
- ✅ Graceful cleanup on signal termination
- ✅ Stack trace display for debugging
- ✅ Integration with core.func message functions
- ✅ Container-agnostic (works in Proxmox + LXC)
Command Execution
↓
ERROR (non-zero exit)
↓
ERR Trap Triggered
↓
error_handler() called
↓
explain_exit_code() lookup
↓
Display error with line/command
↓
Check for log file
↓
Exit with original code
Exit codes are categorized by source system. See api.func.md for comprehensive mapping documentation.
| Range | Category | Examples |
|---|---|---|
| 0 | Success | (no error) |
| 1-2 | Shell errors | Syntax error, operation not permitted |
| 100-101 | APT errors | Package manager errors |
| 126-139 | System errors | Command not found, segfault, OOM |
| 200-231 | Proxmox custom | Container creation errors |
| 210-234 | Database errors | PostgreSQL, MySQL connection issues |
| 243-254 | Runtime errors | Node.js, Python, npm errors |
| 255 | DPKG fatal | Package system fatal error |
Purpose: Maps numeric exit codes to human-readable descriptions. Shared with api.func for consistency.
Signature:
explain_exit_code()Parameters:
-
$1- Exit code (0-255+)
Returns: Human-readable explanation string
Categories Handled:
- Generic shell errors (1, 2, 126-128, 130, 137, 139, 143)
- Package managers (100-101, 255)
- Python (210-212)
- Databases (PostgreSQL 231-234, MySQL 241-244, MongoDB 251-254)
- Node.js/npm (243-249, 254)
- Proxmox custom (200-231)
- Default: "Unknown error"
Usage Examples:
# Example 1: Look up error code
explain_exit_code 127
# Output: "Command not found"
# Example 2: In error logging
error_desc=$(explain_exit_code "$exit_code")
echo "Error: $error_desc" >> /tmp/error.log
# Example 3: Unknown code
explain_exit_code 999
# Output: "Unknown error"Purpose: Main error handler triggered by ERR trap. Displays detailed error information and exits.
Signature:
error_handler()Parameters:
-
$1(optional) - Exit code (default: current $?) -
$2(optional) - Command that failed (default: $BASH_COMMAND) -
$3(optional) - Line number (default: ${BASH_LINENO[0]})
Returns: Exits with original exit code (does not return)
Output Format:
[ERROR] in line 42: exit code 1 (General error): while executing command curl https://api.example.com
--- Last 10 lines of log file ---
[log content]
------------------------------------
Implementation Pattern:
error_handler() {
local exit_code=${1:-$?}
local command=${2:-${BASH_COMMAND:-unknown}}
local line_number=${BASH_LINENO[0]:-unknown}
# If successful, return silently
if [[ "$exit_code" -eq 0 ]]; then
return 0
fi
# Get human-readable error description
local explanation=$(explain_exit_code "$exit_code")
# Show cursor (might be hidden by spinner)
printf "\e[?25h"
# Display error using color messages
if declare -f msg_error >/dev/null 2>&1; then
msg_error "in line ${line_number}: exit code ${exit_code} (${explanation}): while executing command ${command}"
else
echo -e "\n${RD}[ERROR]${CL} in line ${line_number}: exit code ${exit_code}: ${command}\n"
fi
# Log error details if log file configured
if [[ -n "${DEBUG_LOGFILE:-}" ]]; then
{
echo "------ ERROR ------"
echo "Timestamp : $(date '+%Y-%m-%d %H:%M:%S')"
echo "Exit Code : $exit_code ($explanation)"
echo "Line : $line_number"
echo "Command : $command"
echo "-------------------"
} >> "$DEBUG_LOGFILE"
fi
# Show last lines of log if available
local active_log="$(get_active_logfile)"
if [[ -s "$active_log" ]]; then
local log_lines=$(wc -l < "$active_log")
echo "--- Last 10 lines of log ---"
tail -n 10 "$active_log"
echo "----------------------------"
fi
exit "$exit_code"
}Usage Examples:
# Example 1: Automatic trap (recommended)
trap 'error_handler $? "$BASH_COMMAND" $LINENO' ERR
# Error automatically caught and handled
# Example 2: Manual invocation (testing)
error_handler 1 "curl https://api.example.com" 42
# Output: Detailed error with line number
# Example 3: In conditional
if ! some_command; then
error_handler $? "some_command" $LINENO
fiPurpose: Cleanup handler called on normal script exit or error.
Signature:
on_exit()Parameters: None
Returns: Exits with captured exit code
Behavior:
- Captures current exit code
- Removes lock files if present
- Exits with original exit code
Implementation Pattern:
on_exit() {
local exit_code="$?"
# Cleanup lock files
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
# Preserve exit code
exit "$exit_code"
}Trap Configuration:
trap on_exit EXIT # Always called on exitPurpose: Handler for Ctrl+C (SIGINT) signal. Allows graceful shutdown.
Signature:
on_interrupt()Parameters: None
Returns: Exits with code 130 (standard SIGINT exit code)
Output: Displays "Interrupted by user (SIGINT)" message
Implementation Pattern:
on_interrupt() {
echo -e "\n${RD}Interrupted by user (SIGINT)${CL}"
exit 130
}Trap Configuration:
trap on_interrupt INT # Called on Ctrl+CUsage Example:
# Script interrupted by user:
# Ctrl+C pressed
# → on_interrupt() triggers
# → "Interrupted by user (SIGINT)" displayed
# → Exit with code 130Purpose: Handler for SIGTERM signal. Allows graceful shutdown on termination.
Signature:
on_terminate()Parameters: None
Returns: Exits with code 143 (standard SIGTERM exit code)
Output: Displays "Terminated by signal (SIGTERM)" message
Implementation Pattern:
on_terminate() {
echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}"
exit 143
}Trap Configuration:
trap on_terminate TERM # Called on SIGTERMUsage Example:
# System sends SIGTERM:
# kill -TERM $PID executed
# → on_terminate() triggers
# → "Terminated by signal (SIGTERM)" displayed
# → Exit with code 143Purpose: Sets up all error traps and signal handlers. Called once at script start.
Signature:
catch_errors()Parameters: None
Returns: No explicit return value (configures traps)
Traps Configured:
-
ERR→error_handler()- Catches command failures -
EXIT→on_exit()- Cleanup on any exit -
INT→on_interrupt()- Handle Ctrl+C -
TERM→on_terminate()- Handle SIGTERM -
RETURN→error_handler()- Catch function errors
Implementation Pattern:
catch_errors() {
# Set strict mode
set -Eeuo pipefail
# Configure traps
trap 'error_handler $? "$BASH_COMMAND" $LINENO' ERR
trap on_exit EXIT
trap on_interrupt INT
trap on_terminate TERM
trap 'error_handler $? "$BASH_COMMAND" $LINENO' RETURN
}Usage Examples:
# Example 1: Alpine container script
#!/bin/sh
source <(curl -fsSL .../core.func)
source <(curl -fsSL .../error_handler.func)
load_functions
catch_errors
# Now all signals handled automatically
update_os
# Example 2: Proxmox host script
#!/bin/bash
source <(curl -fsSL .../core.func)
source <(curl -fsSL .../error_handler.func)
load_functions
catch_errors
# Safe to proceed with error handling
create_containerActive Log Detection:
# In build.func/install.func:
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log"
INSTALL_LOG="/root/install-${SESSION_ID}.log"
SILENT_LOGFILE="$(get_active_logfile)" # Points to appropriate logWhen command fails in silent():
- Last 10 lines of log file are displayed
- Full log path shown if more than 10 lines
- Error message includes line number where failure occurred
- Command that failed is displayed
From Proxmox host:
# Host-side container creation log
/tmp/create-lxc-<SESSION_ID>.log
# View error details
tail -50 /tmp/create-lxc-550e8400.log
grep ERROR /tmp/create-lxc-*.log
# Development mode persistent logs
/var/log/community-scripts/create-lxc-<SESSION_ID>-<TIMESTAMP>.logFrom inside LXC container:
# Container installation log
/root/install-<SESSION_ID>.log
# View recent errors
tail -20 /root/install-550e8400.log#!/bin/bash
set -Eeuo pipefail
source <(curl -fsSL .../core.func)
source <(curl -fsSL .../error_handler.func)
load_functions
catch_errors # MUST be called before any real work
# Now safe - all signals handled# Use Proxmox custom codes for container-specific errors
if [[ "$CTID" -lt 100 ]]; then
msg_error "Container ID must be >= 100"
exit 205 # Proxmox custom code
fi
# Use standard codes for common errors
if ! command -v curl &>/dev/null; then
msg_error "curl not installed"
exit 127 # Command not found
fi# In error_handler, DEBUG_LOGFILE receives:
DEBUG_LOGFILE="/tmp/debug.log"
# All errors logged with timestamp and details
{
echo "Error at $(date)"
echo "Exit code: $exit_code"
echo "Command: $command"
} >> "$DEBUG_LOGFILE"# Setup signal handlers for cleanup
cleanup() {
[[ -f "$temp_file" ]] && rm -f "$temp_file"
[[ -d "$temp_dir" ]] && rm -rf "$temp_dir"
}
trap cleanup EXIT
# Now temporary files always cleaned up# Force error for testing
false # Triggers error_handler
# or
exit 1 # Custom error
# Verify error handling works correctly
# Check log files and messages# Via environment variable
DEV_MODE_TRACE=true bash script.sh
# Or in script
set -x # Show all commands
trap 'error_handler $? "$BASH_COMMAND" $LINENO' ERR# Show full log file instead of last 10 lines
DEBUG_LOGFILE="/tmp/full-debug.log"
# After error, review complete context
less /tmp/full-debug.log# Manually trigger error handler
bash -c 'source <(curl -fsSL .../error_handler.func); catch_errors; exit 42'
# Should display:
# [ERROR] in line N: exit code 42 (Unknown error): ...- Assign code in appropriate range (see Exit Code Reference)
- Add description to
explain_exit_code()in both:- error_handler.func
- api.func (for consistency)
- Document in exit code table
- Update error mapping documentation
Example: Make error message more helpful:
# Before:
"Container ID must be >= 100"
# After:
"Invalid CTID: $CTID. Container IDs must be >= 100. Current range: 100-999"# Test INT signal (Ctrl+C)
bash -c 'source <(curl -fsSL .../error_handler.func); catch_errors; sleep 30' &
PID=$!
sleep 1
kill -INT $PID
wait
# Test TERM signal
bash -c 'source <(curl -fsSL .../error_handler.func); catch_errors; sleep 30' &
PID=$!
sleep 1
kill -TERM $PID
wait- Error handler is required for all scripts (ensures safe cleanup)
- Exit codes are standardized (0 = success, 1-255 = specific errors)
- Signals are trapped to allow graceful shutdown
- Lock files are automatically cleaned on exit
- Log files contain full error context for debugging