Error Presentation

The framework’s exception presentation path selects a response format from the execution context and request headers, then resolves a view under the configured error-view directory. CLI requests render CLI templates; non-CLI requests whose Accept header contains text/html render HTML templates. Other non-CLI requests receive a direct response instead of a rendered view.

How the flow branches

flowchart TD
    init["Exceptions::initialize"] --> register["Register exceptionHandler callback"]
    register --> event["Exception event"]
    event --> handler["exceptionHandler(Throwable)"]
    handler --> cliCheck{"is_cli()?"}
    cliCheck -- "Yes: CLI" --> render["render(exception, statusCode)"]
    cliCheck -- "No" --> status["Set status and HTTP header"]
    status --> accept{"Accept contains text/html?"}
    accept -- "No" --> direct["respond development diagnostics or empty body"]
    direct --> terminate["send and exit"]
    accept -- "Yes" --> render
    render --> context{"is_cli()"}
    context -- "true" --> cliPath["CLI error-view directory"]
    context -- "false" --> htmlPath["HTML error-view directory"]
    cliPath --> view["determineView and include selected view"]
    htmlPath --> view
    view --> finish["exit(exitCode)"]

Exceptions::initialize in imspr/system/Debug/Exceptions.php contains the registration of exceptionHandler as the PHP exception handler; it registers the callback rather than calling the handler there. When an exception reaches that callback, exceptionHandler receives only a Throwable, derives a status and exit code, sets the HTTP status and header for non-CLI requests, and hands the exception and status code to render when the request proceeds to view rendering. No separate application bootstrap invocation was retrieved, so registration reachability and successful execution are not established.

Config\Exceptions sets errorViewPath to APPPATH . 'Views/errors' in imspr/app/Config/Exceptions.php. render appends cli/ when is_cli() is true and html/ otherwise.

determineView initially selects production.php. A truthy normalized display_errors setting changes that selection to error_exception.php. A PageNotFoundException then takes precedence and selects error_404.php. If that exception branch does not apply and is_file($template_path . 'error_' . $exception->getCode() . '.php') finds a matching status-code view, the method selects error_<code>.php; otherwise it returns the current production-or-debug selection. render collects the exception variables, extracts them for the view, includes the selected file, and emits its buffer.

CLI variants

[
    {
        "label": "404",
        "body": "When determineView receives a PageNotFoundException, it selects `imspr/app/Views/errors/cli/error_404.php`. The view calls `CLI::error('ERROR: ' . $code)`, writes `$message`, and emits a new line."
    },
    {
        "label": "Exception",
        "body": "`imspr/app/Views/errors/cli/error_exception.php` presents an uncaught exception with its type, message, filename, and line number. It adds a backtrace only when `SHOW_DEBUG_BACKTRACE` is defined and exactly true."
    },
    {
        "label": "Production",
        "body": "`imspr/app/Views/errors/cli/production.php` includes `imspr/app/Views/errors/cli/error_exception.php` rather than defining a separate production format."
    }
]

HTML diagnostic presentation

[
    {
        "title": "HTML exception view",
        "body": "`imspr/app/Views/errors/html/error_exception.php` receives extracted `$title`, `$file`, `$line`, and `$trace` values from render. It reads the displayed code and message directly from `$exception->getCode()` and `$exception->getMessage()` rather than from extracted `$type`, `$code`, and `$message` variables. It displays the exception title, source location, and diagnostic tabs for Backtrace, Server, Request, Response, Files, and Memory. The title is passed through `htmlspecialchars` with UTF-8 substitution, while the exception message is output directly."
    },
    {
        "title": "debug.css",
        "body": "The HTML exception template reads `debug.css` from its own directory and embeds the result in the page. The inspected stylesheet selector `.tabs a.active` has unresolved comment-boundary status, so the source does not establish that the stylesheet is active at runtime."
    },
    {
        "title": "debug.js",
        "body": "The HTML exception template reads `debug.js` from its own directory. The script source looks up the element with `document.getElementById('tabs')`, associates tab links with content elements, marks the first tab active, and hides the remaining content elements."
    }
]

[!WARNING] This source establishes the presentation logic, not deployment reachability or deployed settings. Although Exceptions::initialize contains the handler registration, no application bootstrap invocation was retrieved. The non-HTML response exposes collected diagnostics only when ENVIRONMENT === 'development'; otherwise its body is empty. HTML view selection depends on the deployed display_errors value, which is not established here. The HTML exception template reads debug.css, but the inspected .tabs a.active selector has unresolved comment-boundary status, so stylesheet execution is not established. The HTML exception template directly outputs the raw exception message and exposes detailed diagnostic context. When the CLI path selects production.php, that view includes the detailed exception template, so a reduced production CLI presentation is not source-proven.

Updated