Skip to content

Troubleshooting ​

Images return 404 after upload ​

The files are on the public disk but the web server cannot reach them.

  1. Run php artisan storage:link. media-library:install does this when it can.
  2. Check APP_URL. The public disk builds URLs from it, so http://localhost in production produces broken links.
  3. Check MEDIA_LIBRARY_DISK (or disk in 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:work

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

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:

LimitWhereEffect
upload.max_file_sizeConfig or maxFileSize()The whole file, in kilobytes. Over it, the upload stops with "This file is larger than the limit".
post_max_sizephp.iniMust be larger than chunk_size plus a little overhead.
upload_max_filesizephp.iniEach 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.enabled needs a working tenancy.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.strict to false only 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:assets

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

Commercial licence. One licence per production project. Terms · Privacy · Refunds