Fix bin/publish: use correct .env path for rspade_system Fix bin/publish script: prevent grep exit code 1 from terminating script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
289 lines
10 KiB
Plaintext
Executable File
289 lines
10 KiB
Plaintext
Executable File
NAME
|
|
error_handling - RSX framework error handling patterns and shouldnt_happen()
|
|
|
|
SYNOPSIS
|
|
Error handling philosophy, fail-loud patterns, and sanity check functions
|
|
|
|
DESCRIPTION
|
|
The RSX framework enforces strict error handling that prioritizes early
|
|
detection and clear failure over silent continuation. This document covers
|
|
error handling patterns, the shouldnt_happen() function, and examples of
|
|
proper failure handling in security-critical and framework contexts.
|
|
|
|
CORE PHILOSOPHY
|
|
Fail Loud, Not Silent:
|
|
- Errors must be immediately apparent during development
|
|
- No silent fallbacks or alternative code paths
|
|
- Exception handlers should ONLY format error display, not provide alternatives
|
|
- One deterministic way to do things
|
|
|
|
No Defensive Coding for Core Classes:
|
|
- Core framework classes in /app/RSpade/Core/ are ALWAYS present
|
|
- Never check if core classes exist: if (typeof Rsx_Manifest !== 'undefined')
|
|
- Just use them directly: Rsx_Manifest.define()
|
|
- The build system guarantees core classes are present
|
|
|
|
SHOULDNT_HAPPEN() FUNCTION
|
|
Purpose:
|
|
Explicitly fail when encountering "impossible" conditions that indicate
|
|
broken assumptions or corrupted application state.
|
|
|
|
When to Use:
|
|
- After loading files, if expected classes don't exist
|
|
- When required files are missing after checking they should exist
|
|
- When database operations return unexpected null values
|
|
- When array keys that must exist are missing
|
|
- Any time you write a comment like "this shouldn't happen"
|
|
- When critical resources fail to initialize
|
|
- When configuration validation fails in unexpected ways
|
|
|
|
PHP Usage Examples:
|
|
// Class loading validation
|
|
if (!class_exists($expected_class)) {
|
|
shouldnt_happen("Class {$expected_class} should have been loaded in Phase 3");
|
|
}
|
|
|
|
// File system validation
|
|
if (!file_exists($required_file)) {
|
|
shouldnt_happen("Required config file missing: {$required_file}");
|
|
}
|
|
|
|
// Database state validation
|
|
$user = User::find($user_id);
|
|
if (!$user && $user_id > 0) {
|
|
shouldnt_happen("User ID {$user_id} should exist based on session data");
|
|
}
|
|
|
|
// Array key validation
|
|
if (!isset($config['required_setting'])) {
|
|
shouldnt_happen("Config missing required_setting after validation");
|
|
}
|
|
|
|
// Resource initialization
|
|
if (!$this->manifest_data) {
|
|
shouldnt_happen("Manifest data not loaded after successful build");
|
|
}
|
|
|
|
JavaScript Usage Examples:
|
|
// DOM element validation
|
|
if (!element) {
|
|
shouldnt_happen(`Required DOM element #${elementId} not found`);
|
|
}
|
|
|
|
// API response validation
|
|
if (!data.requiredField) {
|
|
shouldnt_happen('API response missing required field: requiredField');
|
|
}
|
|
|
|
// Framework state validation
|
|
if (!Rsx._initialized) {
|
|
shouldnt_happen('Rsx framework not initialized before use');
|
|
}
|
|
|
|
// Component validation
|
|
if (!this.template_rendered) {
|
|
shouldnt_happen('Component ready() called before template render');
|
|
}
|
|
|
|
SECURITY-CRITICAL ERROR HANDLING
|
|
Never Continue on Security Failures:
|
|
Security validation must fail loudly. Never provide fallback paths
|
|
that could compromise security.
|
|
|
|
String Sanitization Example:
|
|
// ❌ CATASTROPHIC - Silent security failure
|
|
try {
|
|
$clean = Sanitizer::sanitize($user_input);
|
|
} catch (Exception $e) {
|
|
$clean = $user_input; // DISASTER - unsanitized data continues
|
|
}
|
|
|
|
// ✅ CORRECT - Fail loudly on security failure
|
|
$clean = Sanitizer::sanitize($user_input); // Let it throw if it fails
|
|
|
|
Authentication Example:
|
|
// ❌ BAD - Silent fallback to unauthenticated
|
|
try {
|
|
$user = Auth::validateToken($token);
|
|
} catch (Exception $e) {
|
|
$user = null; // Dangerous - proceeds without authentication
|
|
}
|
|
|
|
// ✅ GOOD - Fail loudly on auth failure
|
|
$user = Auth::validateToken($token); // Let it throw if invalid
|
|
|
|
Authorization Example:
|
|
// ❌ BAD - Silent permission failure
|
|
if (!$user->hasPermission('admin')) {
|
|
// Log error but continue anyway
|
|
Log::error('Permission denied');
|
|
return $default_view; // WRONG - shows content without permission
|
|
}
|
|
|
|
// ✅ GOOD - Fail loudly on permission failure
|
|
if (!$user->hasPermission('admin')) {
|
|
throw new UnauthorizedException('Admin access required');
|
|
}
|
|
|
|
FRAMEWORK ERROR PATTERNS
|
|
No Alternative Code Paths:
|
|
The framework should have ONE deterministic way to do things.
|
|
No redundant fallback systems.
|
|
|
|
Examples of Anti-Patterns:
|
|
// ❌ BAD - Alternative fallback system
|
|
try {
|
|
$result = NewApiService::process($data);
|
|
} catch (Exception $e) {
|
|
$result = LegacyApiService::process($data); // WRONG
|
|
}
|
|
|
|
// ❌ BAD - Silent failure continuation
|
|
if (!$critical_resource) {
|
|
return; // WRONG - silent continue
|
|
}
|
|
|
|
// ❌ BAD - Defensive existence checks for core classes
|
|
if (class_exists('Rsx_Manifest')) {
|
|
Rsx_Manifest::register(); // WRONG - core classes always exist
|
|
}
|
|
|
|
Correct Patterns:
|
|
// ✅ GOOD - Single path, fail loudly
|
|
$result = NewApiService::process($data); // Let it throw
|
|
|
|
// ✅ GOOD - Explicit failure on missing resources
|
|
if (!$critical_resource) {
|
|
shouldnt_happen("Critical resource not initialized");
|
|
}
|
|
|
|
// ✅ GOOD - Direct usage of core classes
|
|
Rsx_Manifest::register(); // Core classes guaranteed present
|
|
|
|
EXCEPTION HANDLING GUIDELINES
|
|
Exception Handlers Should Only Format:
|
|
Exception handlers should format error display, not provide
|
|
alternative functionality.
|
|
|
|
Web Error Pages:
|
|
// ✅ GOOD - Format error for user display
|
|
try {
|
|
return $controller->handle($request);
|
|
} catch (Exception $e) {
|
|
return view('errors.500', ['error' => $e->getMessage()]);
|
|
}
|
|
|
|
API Error Responses:
|
|
// ✅ GOOD - Format error for API response
|
|
try {
|
|
$data = $service->processRequest($request);
|
|
} catch (ValidationException $e) {
|
|
return response()->json(['error' => $e->errors()], 422);
|
|
}
|
|
|
|
Development Error Display:
|
|
// ✅ GOOD - Enhanced error display for development
|
|
try {
|
|
return $result;
|
|
} catch (Exception $e) {
|
|
if (config('app.debug')) {
|
|
return $this->formatDevelopmentError($e);
|
|
}
|
|
throw $e; // Re-throw in production
|
|
}
|
|
|
|
DEBUGGING ERROR PATTERNS
|
|
Use rsx_dump_die() for Development:
|
|
Preferred debugging function that halts execution after output.
|
|
Use liberally during debugging, remove after fixing issues.
|
|
|
|
Examples:
|
|
rsx_dump_die($user); // Debug single value
|
|
rsx_dump_die($request, $params, $result); // Debug multiple values
|
|
|
|
Never Hide Debugging Information:
|
|
// ❌ BAD - Hidden debug information
|
|
try {
|
|
rsx_dump_die($debug_data);
|
|
} catch (Exception $e) {
|
|
// Silent ignore - WRONG
|
|
}
|
|
|
|
// ✅ GOOD - Let debug output show
|
|
rsx_dump_die($debug_data); // Always visible
|
|
|
|
VALIDATION ERROR HANDLING
|
|
Input Validation:
|
|
Input validation should throw exceptions immediately when validation
|
|
fails. Never continue with invalid data.
|
|
|
|
Model Validation:
|
|
// ✅ GOOD - Fail on validation error
|
|
$user = new User($data);
|
|
$user->validate(); // Throws if invalid
|
|
$user->save();
|
|
|
|
// ❌ BAD - Continue with invalid data
|
|
$user = new User($data);
|
|
if (!$user->validate()) {
|
|
$user->email = 'default@example.com'; // WRONG
|
|
}
|
|
$user->save();
|
|
|
|
Configuration Validation:
|
|
// ✅ GOOD - Fail on invalid config
|
|
if (!config('app.key')) {
|
|
shouldnt_happen('Application key not configured');
|
|
}
|
|
|
|
// ❌ BAD - Default fallback config
|
|
$key = config('app.key') ?: 'default-key'; // WRONG
|
|
|
|
TESTING ERROR SCENARIOS
|
|
Always Test the Failure Path:
|
|
Ensure errors are visible and properly formatted during development.
|
|
|
|
Error Testing Examples:
|
|
// Test that exceptions are thrown
|
|
$this->expectException(ValidationException::class);
|
|
$service->processInvalidData($bad_data);
|
|
|
|
// Test error message content
|
|
try {
|
|
$service->processData(null);
|
|
$this->fail('Expected exception not thrown');
|
|
} catch (Exception $e) {
|
|
$this->assertStringContains('Data cannot be null', $e->getMessage());
|
|
}
|
|
|
|
// Test shouldnt_happen() scenarios
|
|
try {
|
|
$service->processWithMissingDependency();
|
|
$this->fail('shouldnt_happen not triggered');
|
|
} catch (RuntimeException $e) {
|
|
$this->assertStringContains('shouldnt_happen', $e->getMessage());
|
|
}
|
|
|
|
COMMON ANTI-PATTERNS TO AVOID
|
|
Silent Continues:
|
|
Never continue execution when critical operations fail.
|
|
|
|
Redundant Systems:
|
|
Never implement fallback systems that do the same thing differently.
|
|
|
|
Defensive Core Checks:
|
|
Never check if core framework classes exist.
|
|
|
|
Security Fallbacks:
|
|
Never provide fallback authentication or authorization.
|
|
|
|
Default Values on Failure:
|
|
Never substitute default values when validation fails.
|
|
|
|
Try-Catch Workarounds:
|
|
Never use try-catch to work around expected failures.
|
|
|
|
SEE ALSO
|
|
coding_standards - General coding conventions and standards
|
|
console_debug - Debug output and filtering system
|
|
config_rsx - Framework configuration patterns |