naiskit/laravel-oops
Laravel Oops is a lightweight package for cleaner error handling in Laravel apps. It helps replace raw exceptions with friendly, customizable error pages and clearer responses, making failures easier to understand for users and developers. Simple to install and configure without disrupting your work...
default open two-column layout vs. legacy astronaut) and six voice presets (formal, casual, fun, wise, brief, technical). That turns "what does a user see when we fail?" into an explicit, reviewable product choice rather than an engineering default — and lets you pick a different answer for customer-facing surfaces vs. internal tools (e.g. technical for admin back-offices, formal or casual for public checkout).5xx at error, everything else at warning), and surfaces it on the page — optionally embedded in the "what to do next" support line via {ref}. This is a product decision about time-to-resolution and escalation cost: a user-reported code maps directly to a log entry, removing the "can you send a screenshot / what time was it / what URL" loop from support.resources/views/vendor/oops/themes/, lang/vendor/oops/{lang}/tones/). A custom tone only needs the keys it changes; everything else inherits from formal. That is a genuinely cheap path to "our error pages sound like us" — days of work avoided, not weeks.OOPS_LANG is a hard en/id choice and no longer follows app.locale. For a bilingual product this is a fork in the road: either the error page is a deliberate exception to your locale strategy, or the package is the wrong fit. Worth deciding consciously, not discovering in QA.OOPS_POWERED_BY. For B2B or embedded deployments, whether a third-party credit appears in a customer's failure moment is a brand and legal-review question that now has a single flag rather than a code change.SECURITY.md and security test suite assert exception messages, stack traces, and file paths never reach the rendered page even with APP_DEBUG=true + forced rendering. That converts a recurring security-review objection ("does this leak internals on 500s?") into a documented, tested property — useful evidence in vendor questionnaires and pen-test prep.Consider adoption when:
en and id only, or willing to publish and maintain your own lang files for other locales.Look elsewhere — or stay pinned to v1 — when:
app.locale, always." v2 hard-codes OOPS_LANG to en|id. Multi-locale products (5+ languages) should assume they will own the lang files entirely, and a per-request locale switch is no longer free.OOPS_FORCE, oops.statuses, oops.view, oops.messages, oops.default_message, oops.ui, oops.quotes_path, OOPS_QUOTE_GENRES, every OOPS_THEME_* / OOPS_COLOR_* / OOPS_LOGO_* variable, OOPS_ICON_ALIGN, OOPS_BACKGROUND_IMAGE, and OOPS_SHOW_FOOTER are gone, replaced by five settings. Treat this as a migration project, not a composer update.resources/quotes/, oops:quote, QuoteRepository, genres, session-based no-repeat). Removed; the surviving equivalent is the fixed per-status quotes inside the wise tone.Caveat the release notes impose on any roadmap commitment: the v2.0.0 notes are internally inconsistent. The "Removed" section deletes OOPS_SHOW_FOOTER, OOPS_BACKGROUND_IMAGE, OOPS_THEME_*, dark/light mode, mascots, insight lines, and the quote library — while the "Added" and "Changed" sections describe adding oops.theme.icon_align, insight, support, oops.show_footer, oops.theme.background_image, oops.theme.mascot, configurable light/dark forcing, color/accent overrides, and logo replacement. Some "Added" items also appear truncated ("Repl..."). Before quoting capabilities to stakeholders or sequencing an upgrade, verify against the actual tagged source and config/oops.php; the config surface is the thing most likely to differ from the notes. Do not plan a release around the "Added" list until that is reconciled.
To executives (one paragraph): This is a low-cost, well-maintained dependency that upgrades how our product behaves at its worst moments — when a user hits a 404, a permission wall, or a 500. Three things matter commercially. First, trust: instead of raw framework output or a generic "whoops," users get a branded page that explains what happened in a voice we chose, in one of six tones, with a clear next step. Second, support cost: every page carries a reference code that is logged against the real exception, so a user's report resolves in one lookup instead of a back-and-forth — a direct reduction in handling time per incident. Third, security posture: the package ships a documented security policy and an automated test suite proving exception messages, stack traces, and file paths never render, including in debug mode, which answers a standard security-review objection with evidence. It is free, tracked against Laravel 11–13 and PHP 8.2–8.4, and maintained with static analysis and dependency automation — so the cost is adoption, not ownership.
To engineering: Drop-in for Laravel 11–13 on PHP 8.2–8.4. Rendering is composer-driven, themes are single Blade views, tones are single lang files — both publishable and overridable per app without forking. Reference codes are generated per render and logged at error for 5xx and warning otherwise, correlated to the underlying exception. CI covers the full PHP × Laravel matrix, PHPStan/Larastan level 5, and coverage, with Dependabot on composer and actions. Two things to flag: v2.0.0 is breaking — the config surface collapses from dozens of variables to five (OOPS_ENABLED, OOPS_THEME, OOPS_TONE, OOPS_LANG, OOPS_POWERED_BY), so budget a migration rather than a patch bump, and pin v1 if we need the old behavior mid-cycle. And dark mode is gone — each theme has one fixed look regardless of the visitor's OS preference; if that is a requirement for us, we should say so now, because it is a deliberate removal, not an oversight. Finally, before we scope work, reconcile the release notes against the tagged source: the removed and added lists contradict each other on footer, background image, mascot, insight, color overrides, and theme mode, and the notes appear truncated.
How can I help you explore Laravel packages today?