Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Oops Laravel Package

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...

View on GitHub
Deep Wiki
Context7

Getting Started

v2.0.0 is a breaking rewrite: the package no longer has a big config surface. Everything is driven by five .env values, and customization happens through views (themes) and lang files (tones), not config/oops.php.

OOPS_ENABLED=true
OOPS_THEME=default      # default | astronaut
OOPS_TONE=formal        # formal | casual | fun | wise | brief | technical
OOPS_LANG=en            # en | id
OOPS_POWERED_BY=true    # false to white-label the footer

Minimal steps:

composer require naiskit/laravel-oops:^2.0
php artisan vendor:publish --tag=oops-lang   # only if you intend to edit copy
php artisan config:clear                     # env is read into config; stale cache will bite

Where to look first:

  1. resources/lang/{en,id}/errors.php in the package — the error code and title, deliberately identical across every tone.
  2. resources/lang/{en,id}/tones/{tone}.php — message, support line, button labels. Publish with --tag=oops-lang to override.
  3. resources/views/themes/{theme}.blade.php — the entire page design is one Blade file. Override by dropping your own at resources/views/vendor/oops/themes/{name}.blade.php.

First use case: a bilingual app where support staff need something actionable. Set OOPS_TONE=technical and OOPS_LANG=id, hit a dead route, and confirm the page shows the status code, a highlighted reference code, the origin URL (query string stripped), and Home/Back buttons.

curl -s -o /dev/null -w "%{http_code}\n" https://app.test/does-not-exist

Then quote the reference code from the page, grep it in storage/logs/laravel.log, and check it maps to the real exception. That round-trip is the whole point of the reference code and the fastest way to validate the install.

Implementation Patterns

Pick the tone by audience, not by taste. technical explains what the status means and what to check — right for an admin panel or API-adjacent UI. brief is one sentence — right for high-traffic marketing pages where you want the visitor gone fast. wise opens with a fixed per-status quote (the only survivor of the old quote library). formal is the safe default; casual/fun suit consumer products. Since the setting is per-instance, a monolith serving both an internal panel and a storefront needs a runtime override:

// app/Http/Middleware/ErrorToneByArea.php
public function handle($request, Closure $next)
{
    if ($request->is('admin/*')) {
        config(['oops.tone' => 'technical']);
    }
    return $next($request);
}

Verify the config key name against the shipped config/oops.php before relying on this — the release notes describe OOPS_* env vars but the internal key names are not fully restated.

Custom tones are partial by design. A custom tone only needs the keys it changes; everything else falls through to formal. So a brand-voice tone is 5–6 lines, not a full copy of the file:

// lang/vendor/oops/en/tones/friendly.php
return [
    'message' => "We couldn't find that page — no drama, it happens.",
    'support' => 'Still stuck? Give support the code {ref}.',
    'home'    => 'Take me home',
    'back'    => 'Go back',
];

Then OOPS_TONE=friendly. Keep the {ref} token where you want the reference code interpolated; omit it for statuses that don't need one.

Custom themes: copy, don't compose. A theme is one self-contained Blade view. Copy the closest bundled theme (astronaut if you want the old card + side panel + mascots, default for the new open two-column layout) into resources/views/vendor/oops/themes/, rename it, and set OOPS_THEME=mytheme. Because each theme is a single file with its own markup, there are no shared partials to break — but there's also nothing to inherit, so record which upstream commit you forked from. That's your merge base at the next upgrade.

Migrate config copy to lang files before deploying. oops.messages, oops.statuses, oops.view, oops.default_message, and oops.ui are all gone. Any per-status copy your team maintained in config/oops.php will silently vanish and the packaged formal copy will render instead. This is the single most likely source of "why did the wording change?" tickets after the upgrade. Diff your old config against lang/vendor/oops/en/tones/formal.php and port the strings.

Treat the reference code as your support contract. The page shows a short code unique to that render; the package logs it alongside the real exception class, message, and stack trace (error for 5xx, warning for everything else). Teach support to ask for the code, and make sure your log driver actually retains it — a daily channel with 14-day retention is fine; single on a small disk is not. If you route logs to a third-party service, confirm the code lands in a searchable field, not just buried in the message.

Test the rendered page, and the absence of leakage. The package ships a SecurityTest asserting exception messages, stack traces, and file paths never reach the page — replicate that pattern for your custom theme, since a fork can reintroduce a leak:

public function test_custom_theme_does_not_leak_exception_details(): void
{
    config(['oops.theme' => 'company']);

    $this->withoutExceptionHandling(false);
    $response = $this->get('/boom'); // route that throws a RuntimeException with a secret message

    $response->assertStatus(500);
    $response->assertDontSee('SQLSTATE');
    $response->assertDontSee(base_path());
}

White-labelling is now a single flag: OOPS_POWERED_BY=false. If you previously removed the footer by editing views, delete that override — the bundled themes already honour the flag.

Gotchas and Tips

  • The release notes contradict themselves. The "Removed" section kills light/dark mode, oops.theme.icon_align, oops.show_footer, mascots, background images, and every OOPS_THEME_* variable — while the "Added"/"Changed" sections (which read like the accumulated v1.x changelog) describe those same features as new. Do not build against the prose. After upgrading, read the shipped config/oops.php and the theme Blade files directly; that is the only source of truth for which keys still exist.
  • OOPS_LANG no longer follows app.locale. The hardest breaking change to notice, because nothing errors — a German or Indonesian user just gets English. OOPS_LANG accepts en or id. If you serve multiple locales, either pin the value per deployment (separate instances per market) or override config('oops.lang') early in the request lifecycle from your own locale resolver. Adding a third language means shipping lang/vendor/oops/{locale}/tones/*.php yourself — confirm the package resolves an unlisted locale rather than falling back to en before you promise it to a client.
  • OOPS_FORCE is listed as removed (again, see the contradiction above). If you relied on it to preview error pages locally, you lose the ability to eyeball a 503 without causing one. Keep a local-only route that throws the status you want, gated on app()->isLocal(), and never ship it.
  • No light/dark mode. Each theme has exactly one look. Visitors on OS dark mode get the light design. If a client contract requires dark, you need a custom theme — there is no setting for it.
  • Custom logo/icon option is gone. The astronaut theme renders built-in mascots per status; default renders an illustration per status. To put your brand mark back you must fork the theme view. Budget for that; it's not a config toggle anymore.
  • Quote machinery deleted. Remove oops:quote from any scheduler, delete references to QuoteRepository, and drop --tag=oops-quotes from deploy scripts — they will fail the deploy. Swap in --tag=oops-lang if you publish copy.
  • Stale published views. Per-status views and light/dark overrides published under resources/views/vendor/oops/ from v1 will linger and may shadow the new theme resolution. Audit that directory and delete anything that isn't themes/{name}.blade.php.
  • Published lang files are yours to maintain. Once published, new keys added upstream won't appear. Missing keys in a custom tone degrade gracefully (it falls back to formal per key), but a published-and-stale formal.php may render raw keys. Pin the package version and diff lang files on each bump.
  • Platform floor moved. CI covers PHP 8.2/8.3/8.4 × Laravel 11/12/13. Laravel 10 and PHP 8.1 are out — check before starting the upgrade, not during it.
  • Always php artisan config:clear (and view:clear after theme edits). OOPS_* changes appear inert otherwise, which reads as a broken package rather than a cached config.
  • Extension points, in order of cost: OOPS_TONE / OOPS_LANG (free) → custom tone file (a few lines) → published lang edits (maintenance burden) → custom theme view (real fork, track upstream). Reach for the theme only when the layout or brand genuinely can't be satisfied otherwise.
  • Positive signals worth noting for a security review: SECURITY.md, a dedicated leak-prevention test suite, and PHPStan/Larastan level 5 in CI. If you have a compliance gate, cite the security test suite rather than writing your own from scratch — extend it for your theme instead.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle