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

Unexpected Response Bundle Laravel Package

samson/unexpected-response-bundle

A Symfony bundle for handling unexpected HTTP responses, helping applications detect, catch, and present responses that fall outside normal expectations with a structured, consistent approach.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony 2-era bundle, not a Laravel package — treat it as a reference implementation of a pattern rather than a dependency you install into a Laravel app.

If you are evaluating it inside a Symfony project:

  1. Require it with an explicit constraint, since the only tagged release is from 2014:
    composer require "samson/unexpected-response-bundle:^1.0"
    
  2. Register the bundle in app/AppKernel.php (Symfony 2/3 style — there is no Flex recipe, no bundles.php auto-registration, and no service autowiring).
  3. Look first at two files in vendor/samson/unexpected-response-bundle/:
    • the exception class that carries a Response payload,
    • the kernel.exception event listener that unwraps it and returns the response. Those two files are the package; everything else is boilerplate.

First use case — the canonical one it was built for: you are several layers deep in a service (an authentication guard, a rate limiter, a domain invariant check) and need to short-circuit with a redirect or an error response, but you only have a return value to work with. Instead of threading a Response back up through five method signatures, you throw:

throw new UnexpectedResponse(new RedirectResponse('/login'));

The exception listener catches it before Symfony's default error rendering and returns the wrapped response as-is.

If you are a Laravel developer, read the two source files above and then stop — see the Gotchas section for the Laravel equivalent, which you already have in core.

Implementation Patterns

Short-circuit from a domain service. The main value is avoiding Response objects leaking into your service layer signatures. A service method keeps returning its normal type; on the failure path it throws the response-carrying exception. Callers stay clean.

Guards and filters. Auth checks, feature flags, and maintenance-mode checks inside listeners or middleware are natural fits — anywhere you want to bail out with a redirect or 403 without unwinding a return value through the call stack.

API error envelopes. Wrap a JsonResponse with your standard error shape and throw it from a repository or query object when a record is missing or a precondition fails.

Testing. Two levels:

  • Unit: assert the exception type and inspect the wrapped response (getResponse()->getStatusCode()).
  • Functional: hit the route through the kernel and assert the final status/location — this is what actually proves the listener priority is correct.

Integration tip — keep the throw site boring. Wrap the throw in a small named factory (AuthRequired::redirect(), ApiError::notFound($id)) so the rest of the codebase never touches the bundle's class directly. That single indirection is what makes the code portable when you eventually replace the bundle.

Laravel translation of the pattern. You do not need this package. Use:

  • abort(403) / abort(404) inside services — Laravel's HttpException is caught by the exception handler.
  • A custom exception implementing Illuminate\Contracts\Support\Responsable, so render() returns the response you want.
  • App\Exceptions\Handler::render() for global shaping.
  • RedirectResponse thrown from a form request's failedAuthorization().

The Symfony bundle and Laravel's Responsable/abort() are solving the same problem; Laravel's version is in core and maintained.

Gotchas and Tips

It is effectively abandoned. Last release August 2014, one star, zero dependents. There is no Symfony 4/5/6/7 support: the bundle predates bundles.php, autowiring, and the EventDispatcherInterface changes. Do not add it to a modern Symfony app; copy the ~40 lines of listener and exception class into your own src/ instead.

Listener priority is the whole trick. The bundle must run before Symfony's ExceptionListener (which renders the error page). If you copy the code, register at a priority higher than the default 0 — otherwise you get a 500 page and a logged exception instead of your response. This is the #1 thing to verify when porting.

Exceptions are for exceptional paths, not flow control. It is tempting to throw a redirect for every "not logged in" case in every service. That makes stack traces your debugging interface and hides control flow. Restrict it to genuinely terminal paths; ordinary validation should still return values.

Sub-requests and ESI. If the throw happens inside a sub-request, the listener still fires, but the returned response may not be what the parent expects. Test fragmented/embedded rendering explicitly if you use it.

Responses are fully-formed, not templates. Once thrown, nothing downstream runs — no kernel.response listeners that mutate your response will have run yet in the original flow, and any work after the throw site is skipped. Do not rely on finally-style cleanup unless you actually use finally.

Debug mode changes behavior. In dev with the profiler, an uncaught exception that looks handled can still surface in the toolbar. Confirm behavior with prod-like settings before concluding it works.

No config, no extension points. There is no Configuration tree, no service aliases, no way to customize the exception class. If you need an error-code-to-response mapping, that is your code, not the bundle's.

Composer friction. No dev-master stability guarantees, no composer.json branch-alias for modern constraints. A fresh composer require may resolve to a 2014 commit with no Symfony constraint, silently allowing an incompatible framework version. Pin both the bundle and Symfony explicitly and run composer why-not if it refuses to install.

Verdict for a Laravel shop: skip the dependency. Read it as a 40-line case study in "how do I return an HTTP response from a non-controller," then implement it with abort(), Responsable, and Handler::render() — all supported, all tested against current Laravel.

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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels