Error Handling
This page is a stub. Help us expand it!
Overview
Good error handling improves user experience and makes debugging easier. This guide covers patterns for handling errors gracefully in Unraid plugins.
Principles
- Fail gracefully - Don’t crash the entire page
- Log details - Record full error info for debugging
- Show friendly messages - Users see helpful, non-technical text
- Don’t expose internals - Hide paths, stack traces from users
- Provide next steps - Tell users what to do
PHP Error Handling
Try-Catch Pattern
<?
try {
// Risky operation
$result = performOperation();
if (!$result) {
throw new Exception("Operation failed");
}
} catch (Exception $e) {
// Log the real error
syslog(LOG_ERR, "yourplugin: " . $e->getMessage());
// Show user-friendly message
$error = "An error occurred. Please check the logs for details.";
}
?>
<?if (isset($error)):?>
<p class="error"><?=htmlspecialchars($error)?></p>
<?endif;?>
Custom Error Handler
<?
function pluginErrorHandler($errno, $errstr, $errfile, $errline) {
// Log full details
$message = sprintf(
"Error [%d]: %s in %s on line %d",
$errno, $errstr, $errfile, $errline
);
syslog(LOG_ERR, "yourplugin: $message");
// Don't execute PHP's internal error handler
return true;
}
// Enable for your plugin code
set_error_handler("pluginErrorHandler");
// ... your code ...
// Restore default handler
restore_error_handler();
?>
Checking Return Values
<?
// File operations
$content = file_get_contents($file);
if ($content === false) {
$error = "Failed to read configuration file";
syslog(LOG_ERR, "yourplugin: Cannot read $file");
}
// Exec calls
exec("some_command 2>&1", $output, $retval);
if ($retval !== 0) {
$error = "Command failed";
syslog(LOG_ERR, "yourplugin: Command returned $retval: " . implode("\n", $output));
}
?>
User-Friendly Messages
Good vs Bad Error Messages
<?
// BAD - Exposes internal details
$error = "MySQL error: SELECT * FROM table WHERE id=$id failed at /var/www/db.php:45";
// GOOD - User-friendly
$error = "Unable to load settings. Please try again or contact support.";
// BETTER - With action
$error = "Unable to load settings. <a href='settings.php?reload=1'>Click here to retry</a>.";
?>
Error Message Patterns
<?
$errorMessages = [
'file_not_found' => "Configuration file not found. Please reinstall the plugin.",
'permission_denied' => "Permission denied. Check file permissions.",
'connection_failed' => "Could not connect to service. Is it running?",
'invalid_input' => "Invalid input provided. Please check your settings.",
'timeout' => "Operation timed out. Please try again.",
];
function getUserError($code) {
global $errorMessages;
return $errorMessages[$code] ?? "An unexpected error occurred.";
}
?>
Bash Script Error Handling
#!/bin/bash
# Exit on error
set -e
# Error handler
error_handler() {
logger -t "yourplugin" "Error on line $1"
exit 1
}
trap 'error_handler $LINENO' ERR
# Check command success
if ! some_command; then
logger -t "yourplugin" "some_command failed"
exit 1
fi
# Check file exists
if [ ! -f "/path/to/required/file" ]; then
logger -t "yourplugin" "Required file missing"
exit 1
fi
Validation Errors
<?
$errors = [];
// Collect all validation errors
if (empty($_POST['name'])) {
$errors[] = "Name is required";
}
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$errors[] = "Invalid email address";
}
if ($_POST['port'] < 1 || $_POST['port'] > 65535) {
$errors[] = "Port must be between 1 and 65535";
}
// Display all errors together
if (!empty($errors)):
?>
<div class="error-box">
<p><strong>Please correct the following errors:</strong></p>
<ul>
<?foreach ($errors as $err):?>
<li><?=htmlspecialchars($err)?></li>
<?endforeach;?>
</ul>
</div>
<?
endif;
?>
AJAX Error Handling
Server Side
<?
header('Content-Type: application/json');
try {
// Process request
$result = doSomething();
echo json_encode([
'success' => true,
'data' => $result
]);
} catch (Exception $e) {
syslog(LOG_ERR, "yourplugin: " . $e->getMessage());
http_response_code(500);
echo json_encode([
'success' => false,
'error' => 'Operation failed. Check logs for details.'
]);
}
?>
Client Side
$.ajax({
url: '/plugins/yourplugin/action.php',
method: 'POST',
data: formData,
success: function(response) {
if (response.success) {
swal('Success', 'Operation completed', 'success');
} else {
swal('Error', response.error, 'error');
}
},
error: function(xhr, status, error) {
var message = 'Request failed';
try {
var response = JSON.parse(xhr.responseText);
message = response.error || message;
} catch(e) {}
swal('Error', message, 'error');
}
});
Logging Levels
<?
// Use appropriate severity
syslog(LOG_DEBUG, "yourplugin: Debug info"); // Development only
syslog(LOG_INFO, "yourplugin: Informational"); // Normal operations
syslog(LOG_WARNING, "yourplugin: Warning"); // Potential issues
syslog(LOG_ERR, "yourplugin: Error"); // Errors
syslog(LOG_CRIT, "yourplugin: Critical"); // Critical failures
?>
Recovery Patterns
<?
// Retry logic
function withRetry($callback, $maxAttempts = 3, $delay = 1) {
$lastException = null;
for ($i = 0; $i < $maxAttempts; $i++) {
try {
return $callback();
} catch (Exception $e) {
$lastException = $e;
sleep($delay);
}
}
throw $lastException;
}
// Usage
try {
$result = withRetry(function() {
return fetchRemoteData();
});
} catch (Exception $e) {
$error = "Failed after multiple attempts";
}
?>