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

Bugsnag Laravel Package

bugsnag/bugsnag

Bugsnag for PHP automatically reports unhandled exceptions and crashes, plus handled errors, with user info and custom diagnostic data. Works with Laravel, Lumen, Symfony, Silex, Magento, WordPress, and other PHP apps.

View on GitHub
Deep Wiki
Context7

Getting Started

bugsnag/bugsnag is the framework-agnostic engine. In a Laravel app you almost never install it directly — you install bugsnag/bugsnag-laravel, which pulls this package in as the transport/reporting core. Everything below applies either way, because the Laravel service provider exposes the exact same Bugsnag\Client API you'd wire up by hand.

Minimal bootstrap (bare PHP / artisan tinker / a non-Laravel sub-service):

composer require bugsnag/bugsnag
$client = Bugsnag\Client::make(getenv('BUGSNAG_API_KEY'));
Bugsnag\Handler::register($client);   // hooks set_error_handler + set_exception_handler

That's the whole "first use case": uncaught exceptions and fatal errors start flowing to your dashboard. Handler::register() also returns a handler instance, so keep the reference if you want to unregister later (important in tests).

Where to look first:

  1. config/bugsnag.php (published via php artisan vendor:publish --provider="Bugsnag\BugsnagLaravel\BugsnagServiceProvider") — the api_key, notify_release_stages, blacklist/redacted_keys, discard_classes, user, feeds, logger keys.
  2. The Bugsnag\Client public methods — notifyException, notifyError, leaveBreadcrumb, setUser, addMetadata, getConfig. This is 95% of your daily surface area.
  3. Bugsnag\Configuration for the full option list (the docs site calls these "configuration options" per platform, but they map 1:1 to this class).

First concrete use case: let the automatic handler catch your unhandled Throwables, then add one manual notification for the failure mode you actually care about (a failed payment job, a third-party API timeout) so the team sees signal before you've instrumented anything else.

try {
    $gateway->charge($order);
} catch (\Throwable $e) {
    Bugsnag::notifyException($e);
    throw $e; // or swallow, but report before you do
}

Verify end-to-end by throwing a deliberate exception in a staging deploy and checking the release stage, app.version, and the user tab populate correctly. If nothing arrives, the API key, notify_release_stages, or the outbound network is the culprit — in that order.

Implementation Patterns

Wrap, don't replace, exception handling. In Laravel, app/Exceptions/Handler.php::report() is the natural choke point. parent::report($e) already forwards to Bugsnag via the package; add ->context() or ->addMetadata() inside a Bugsnag::registerCallback rather than duplicating notifyException calls scattered across services. Two reports for one exception creates duplicate groups.

Use registerCallback as your single enrichment seam. This runs for both automatic and manual reports, so user, metadata, and severity logic lives in one place:

Bugsnag::registerCallback(function (Bugsnag\Report $report) {
    $report->setUser(['id' => auth()->id(), 'email' => auth()->user()?->email]);
    $report->addMetadata('order', ['id' => request()->route('order')?->id]);
});

Metadata: choose merge or overwrite deliberately. addMetadata($tab, $data) overwrites the tab; passing tab-level data merges only where you ask for it. Mixing the two in one callback will silently drop keys you expected to persist across nested callback registrations. Keep one callback for "always" data and use a separate one for per-notification data.

Severity is an enum, not a string. notifyException($e, Report::SEVERITY_WARNING) — use Report::SEVERITY_INFO for expected domain failures (validation, 402s from a payment provider) so they don't page anyone. The severity_reason is derived automatically from handling context since 3.8 (handled vs unhandled), so don't try to set it.

Breadcrumbs before the crash. The recorder is capped at 50 by default (configurable 0–100 since 3.29). Log meaningful state transitions, not every query:

Bugsnag::leaveBreadcrumb('webhook received', Bugsnag\Breadcrumbs\Breadcrumb::METADATA, ['event' => $type]);

In queued jobs, breadcrumbs from the dispatching request aren't carried over — re-log the job payload at the top of handle().

Feature flags / experiments: $client->addFeatureFlag('checkout_v2', 'treatment') (3.28+) attaches to every subsequent event; Report::getFeatureFlags lets the callback inspect them to tag severity.

Error vs exception: notifyError($message, $severity) for conditions with no Throwable — never fabricate an exception to force a report, you'll pollute grouping with synthetic class names.

Discard at the source. discardClasses accepts exception class names and PHP error constant names (E_NOTICE, E_DEPRECATED). This is cheaper than a callback returning false, which still pays the serialization and transmission cost.

Session/batch behaviour: notifications are batched and flushed at shutdown. In long-running processes (Octane, queue workers, Swoole), call $client->flush() per job/request or the batch never ships — this is the number one "Bugsnag is broken in Octane" cause.

Gotchas and Tips

errorReportingLevel must be a subset of PHP's error_reporting. Since 3.24 (PHP 8 compatibility), any level in your Bugsnag config that isn't in error_reporting is silently dropped. If notices vanish after a PHP upgrade, reconcile the two configs — error_reporting is usually the one that changed.

filters is deprecated in favour of redacted_keys. Redacted keys support strings (exact, case-insensitive) and regexes for wildcards; filters only did case-insensitive substring matching. Cookies and HTTP Basic auth headers are already redacted by default (3.23), but user metadata is only covered if you've configured the keys — check the User tab of a real event before going live.

registerWithPrevious is deprecated. Since 3.23.1 the previous handler is always chained, and PHP's default handler runs too. If you're upgrading, delete the call; if you relied on Bugsnag swallowing the error and exiting 0, watch your CLI exit codes — they now follow PHP's default behaviour.

Out-of-memory errors are only reported because Bugsnag raises the limit by 5 MiB. If a container is hard-capped (Kubernetes limits.memory) that reserve may not be enough; set memoryLimitIncrease higher, or null to disable. OOM reports are also the flakiest thing to debug — the report itself can fail to serialize.

Endpoints default from the API key (3.30). Don't hardcode endpoint unless you're on Bugsnag On-Premise or a proxy; a stale hardcoded endpoint pointing at the old bugsnag.com host will fail silently after the SmartBear migration. Custom endpoints mounted on a sub-path are supported (3.3) — include the path, not just the host.

Guzzle timeouts don't apply to custom clients. Since 3.25 default timeout/connect_timeout are set on internally-created Guzzle instances only. If you inject your own client for proxy/mTLS reasons, replicate the timeouts yourself or a slow network will stall your request shutdown.

display_errors must be off in production. Bugsnag now defers to PHP's default handlers, so leaving it on means stack traces render to users on every reportable error.

Stack frames and paths. projectRoot + the strip-path regex control in-project detection (fixed for repeated substrings in 3.5.1). Misconfigured here means every frame is marked "not in project" and grouping quality collapses. Set projectRoot to base_path() in Laravel and confirm the first frame of a test exception shows as in-project.

Serialization surprises. Backed enums serialize as EnumName::CaseName (value) since 3.27, pure enums to their case name — don't assert on the old JSON scalar in tests. Objects implementing __toString are fine; closures and resources are dropped, so a metadata array containing a closure loses the whole tab in some paths. Pass scalars or JsonSerializable values.

Testing: Handler::register() installs global handlers that leak between tests. Register in setUp, call the returned handler's unregister (or restore_error_handler) in tearDown. Better: inject Bugsnag\Client with a fake/mock transport and assert on notifyException calls rather than asserting on network requests.

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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package