Appearance
Troubleshooting
Images return 404 after upload
The files are on the public disk but the web server cannot reach them.
- Run
php artisan storage:link.media-library:installdoes this when it can. - Check
APP_URL. Thepublicdisk builds URLs from it, sohttp://localhostin production produces broken links. - Check
MEDIA_LIBRARY_DISK(ordiskin the config) points at the disk you expect.
Thumbnails work, larger sizes are missing
The thumb conversion runs during the upload. preview and any conversion with 'queued' => true run on the queue. Start a worker:
bash
php artisan queue:workWith QUEUE_CONNECTION=sync they run inline. To rebuild after a fix, run php artisan media-library:regenerate --missing. See Commands.
The image editor will not open on S3
The editor reads the original pixels in the browser, so the bucket must allow your panel's origin. Add a CORS rule:
json
[{ "AllowedOrigins": ["https://admin.example.com"], "AllowedMethods": ["GET"], "AllowedHeaders": ["*"] }]The editor shows a CORS message when the browser blocks the request. The same applies to a CDN in front of the bucket. See Storage & S3.
Private or S3 links return 403
Temporary URLs and signed links expire after temporary_url_minutes (30 by default), and the library caches each URL for half of that. A 403 on a page that has been open for a long time means the link expired: reload.
If every link fails straight away on S3, check the bucket credentials and region in config/filesystems.php, and that the server clock is correct, because S3 signatures include a timestamp. On a local private disk, links go through a signed route, so a changed APP_KEY or APP_URL invalidates them.
Uploads fail on large files
Files are sent in chunks of upload.chunk_size (5 MB by default), so a 500 MB file is many small requests. Three limits matter:
| Limit | Where | Effect |
|---|---|---|
upload.max_file_size | Config or maxFileSize() | The whole file, in kilobytes. Over it, the upload stops with "This file is larger than the limit". |
post_max_size | php.ini | Must be larger than chunk_size plus a little overhead. |
upload_max_filesize | php.ini | Each chunk is a multipart file upload, so this must also be larger than chunk_size. PHP's default is 2 MB. |
If you cannot raise the PHP limits, lower upload.chunk_size. The minimum the server accepts is 256 KB. A reverse proxy in front of PHP also needs room: nginx's client_max_body_size must exceed the chunk size.
An error saying "The upload was interrupted" means a chunk was rejected or out of order. One person can have at most 20 unfinished uploads. Run media-library:prune to clear abandoned ones.
"Not enough storage left"
A quota is set and the tenant, or the whole app, is full. Raise the quota or delete unused files. Trashed files still count until they are pruned.
403 or 404 on the library outside a panel
Pages outside a Filament panel are off by default. Set this in config/filament-media-library.php:
php
'standalone' => ['enabled' => true],While it is off, the standalone upload and download routes return 404, and <livewire:media-library> and <livewire:media-library-picker> abort with 403. Before you turn it on, register a policy that fits your site. See Outside Filament panels.
The library is empty for a tenant
With tenancy on, strict mode shows nothing when no tenant resolves. That is by design, so one tenant never sees another's files.
- In a panel with
->tenant(...), make sure you opened the library under a tenant URL. - Outside panels,
tenancy.enabledneeds a workingtenancy.resolver. Check that it returns the current tenant in the request that renders the component. - Files uploaded before you turned tenancy on have no tenant and do not match the scope.
- Set
tenancy.stricttofalseonly if you want unresolved requests to see everything.
See Multi-tenancy.
Livewire "Cannot update locked property"
The picker and browser lock their configuration (multiple, maxItems, acceptedFileTypes, folderId, layout and more) so a visitor cannot change them from the browser. The error means something tried to change one after render: a wire:model bound to one of those properties, or a $wire.set() call. Pass options as component attributes when you render it instead:
blade
<livewire:media-library-picker wire:model="coverId" accept="image/*" />Bind only to value, which is what wire:model does by default. Clear your browser cache after an upgrade so old JavaScript does not send stale state.
Styles or scripts do not load
Run:
bash
php artisan filament:assetsDo it on every deploy, because the assets are copied to public/. The library's CSS loads on demand on pages that use it, and you do not need to edit your Filament theme. If you cache views or assets behind a CDN, clear them after upgrading the package.
Still stuck
Search the error text in this page first. If you open a support request, include the package version, Filament and Livewire versions, the disk driver and the browser console output.