Component JS/CSS asset routes return 500 instead of 404 when the asset doesn't exist
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 75/100
Research direction
The issue is in SupportJsModules.php and SupportCssModules.php. Look at the provide() method in each file. The fix is to catch ComponentNotFoundException and check for the existence of scriptModuleSrc/styleModuleSrc methods and the file they point to, returning a 404 response instead of throwing an exception. Test by making requests to the asset routes as shown in the issue description and verifying they return 404.
Written by the indexing model from the issue text.
Description
Livewire version
v4.3.3
Laravel version
v13.18.1
PHP version
8.4.23
Browser and operating system
curl/8.7.1 on macOS (no browser involved — these are plain GET requests)
Describe the issue you're experiencing
The three per-component asset routes resolve the component straight out of the URL and throw on
every miss, so a request for an asset that isn't there comes back as a 500 instead of a 404:
| Request | Thrown in | Status |
|---|---|---|
/livewire-{hash}/js/{unknown}.js |
LivewireManager::new() → ComponentNotFoundException |
500 |
/livewire-{hash}/js/{real-component}.js (component has no script module) |
Exception('Component ... does not have a script source.') |
500 |
/livewire-{hash}/css/{real-component}.css |
Exception('... does not have a style source.') |
500 |
/livewire-{hash}/css/{real-component}.global.css |
Exception('... does not have a global style source.') |
500 |
The endpoints are SupportJsModules::provide() and SupportCssModules::provide():
Two consequences in production:
- It pages you. A single
curl https://example.com/livewire-{hash}/js/x.jsraised a
ComponentNotFoundExceptionalert in Laravel Nightwatch, reported as a 500 HTTP request. The
{hash}prefix is derived fromAPP_KEY, but it ships in the<script src>of every page
that renders Livewire, so anything that has loaded one public page can hit these routes. - Every real component 500s too, not just invented names. The overwhelmingly common case is
a component with noscriptModuleSrc()/styleModuleSrc()at all, and that is the branch that
throws a bare\Exception— so an app cannot even filter it by exception class.
Both are "the asset isn't there", which is what 404 means. Nothing in these two closures does
anything but read a file off disk, so there is no failure mode here that a 500 describes
correctly.
Code snippets to reproduce the issue
Fresh Laravel 13 app with livewire/livewire:^4.3, one ordinary component:
// app/Livewire/Counter.php
<?php
namespace App\Livewire;
use Livewire\Component;
class Counter extends Component
{
public function render()
{
return <<<'HTML'
<div>Hello</div>
HTML;
}
}
Grab the endpoint prefix (it is in the <script src> of any page rendering Livewire, or:
php artisan tinker --execute 'echo \Livewire\Mechanisms\HandleRequests\EndpointResolver::prefix();'
# /livewire-a1b2c3d4
Then:
# 1. a component that does not exist — ComponentNotFoundException
curl -i https://example.test/livewire-a1b2c3d4/js/nope.js
# HTTP/1.1 500 Internal Server Error ("Unable to find component: [nope]")
# 2. the real component above, which simply has no script module
curl -i https://example.test/livewire-a1b2c3d4/js/counter.js
# HTTP/1.1 500 Internal Server Error ("Component counter does not have a script source.")
# 3. same for both CSS endpoints
curl -i https://example.test/livewire-a1b2c3d4/css/counter.css
curl -i https://example.test/livewire-a1b2c3d4/css/counter.global.css
# HTTP/1.1 500 Internal Server Error
All four are 500 with APP_DEBUG either on or off.
How do you expect it to work?
All four should be 404. The requested asset does not exist; that is a client error, not a
server fault, and it should not reach the app's exception reporting.
A minimal shape, in SupportJsModules::provide() (and the same in SupportCssModules::provide()
for both of its routes):
try {
$instance = app('livewire')->new($component);
} catch (ComponentNotFoundException) {
abort(404);
}
if (! method_exists($instance, 'scriptModuleSrc')) {
abort(404);
}
$path = $instance->scriptModuleSrc();
if (! file_exists($path)) {
abort(404);
}
Happy to open a PR along those lines if the approach looks right.
For anyone who lands here first, the app-side workaround is to render these paths as 404 in
bootstrap/app.php — the route closures live in the vendor package and are registered before the
application's own routes, so they cannot be overridden by re-declaring the URI:
->withExceptions(function (Exceptions $exceptions): void {
$isLivewireComponentAsset = function (Request $request): bool {
$prefix = trim(EndpointResolver::prefix(), '/');
return $request->is("{$prefix}/js/*", "{$prefix}/css/*");
};
$exceptions->render(fn (Throwable $e, Request $request) => $isLivewireComponentAsset($request)
? response('', 404)
: null);
$exceptions->dontReportWhen(fn (Throwable $e) => $isLivewireComponentAsset(request()));
})
Please confirm
- I have provided easy and step-by-step instructions to reproduce the bug.
- I have provided code samples as text and NOT images.
- I understand my bug report will be removed if I haven't met the criteria above.
- Dominant language
- PHP
- Stars
- 23.6k
- Forks
- 1.7k
- Avg merge
- 20h 11m
- Merged PRs (30d)
- 64
Getting set up
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from livewire/livewire
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 42/100
Maintainers usually reply within 1 day
All issues in livewire/livewire
Similar issues
-
sync-en
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
bug Feature: Kiosk
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
Infrastructure: actions Module: zmscitizenapi Module: zmsentities php Type: Bug unit tests
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
it-at-m/eappointment#3480 ·
Maintainers usually reply within 1 day
-
HttpClient
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
CI: composer install fails — league/flysystem 1.x blocked by security advisory GHSA-cxf4-7mrp-vvprOpendevops type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 1 day