Skip to content

Asset upload after sorting by lastModified fails, breaks asset list #11961

Description

@Alex--C

Bug description

Trying to upload an asset after sorting the asset list by the "last modified" column results in a server error. Afterwards, the asset list can no longer be viewed in the CP.

How to reproduce

  • Set 'throw' => true on your filesystem
  • Open asset overview in CP (/cp/assets/browse/assets)
  • Sort by "Last Modifed" column (direction does not matter)
  • Upload a new asset
  • The asset upload fails
  • Refresh the page: Loading the assets now results in an error, the list can no longer be displayed

We narrowed the issue down to the following:

  • Statamic stores the currently used indexes in a stache entry "stache::indexes::assets::assets::_indexes". By default this key contains ["path", "folder", "basename"]
  • When sorting the list by "Last Modifed", the stache entry is updated and now contains ["path", "folder", "last_modified"]
  • When a new asset is saved, the indexes are updated before the metadata of the new asset are stored (https://github.com/statamic/cms/blob/5.x/src/Assets/AssetRepository.php#L148)
  • When last_modified is present in the currently used index list, the indexer tries to access lastModified() on the asset. This will try to read the metadata, which does not yet exist. This leads to an error.
  • Since the error is not handled, the request will abort before the metadata for the new asset was stored, but after the asset itself was saved on the drive
  • Reloading the asset list then errors out because of the missing metadata for an asset

I can think of a few different approaches to solve this, but I'm sure someone with more "under the hood" experience knows which one would be the proper way to handle this.
Each of these individually should fix the issue:

  • Store asset metadata before updating the indexes
  • Don't update the currently used indexes based on the sorting
  • Handle the missing metadata in lastModified() (return null?)

Logs

[2025-07-15 12:44:49] local.ERROR: Unable to read file from location: img/.meta/new-asset.jpg.yaml. Unable to read file from location: assets/img/.meta/new-asset.jpg.yaml. {"userId":"asdf","exception":"[object] (League\\Flysystem\\UnableToReadFile(code: 0): Unable to read file from location: img/.meta/new-asset.jpg.yaml. Unable to read file from location: assets/img/.meta/new-asset.jpg.yaml. at /Users/foobar/statamic-cms/vendor/league/flysystem/src/UnableToReadFile.php:24)
[stacktrace]
#0 /Users/foobar/statamic-cms/vendor/league/flysystem-path-prefixing/PathPrefixedAdapter.php(50): League\\Flysystem\\UnableToReadFile::fromLocation('img/.meta/jake-...', 'Unable to read ...', Object(League\\Flysystem\\UnableToReadFile))
#1 /Users/foobar/statamic-cms/vendor/league/flysystem/src/Filesystem.php(76): League\\Flysystem\\PathPrefixing\\PathPrefixedAdapter->read('img/.meta/jake-...')
#2 /Users/foobar/statamic-cms/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php(291): League\\Flysystem\\Filesystem->read('img/.meta/jake-...')
#3 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Filesystem/AbstractAdapter.php(14): Illuminate\\Filesystem\\FilesystemAdapter->get('img/.meta/jake-...')
#4 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Assets/Asset.php(252): Statamic\\Filesystem\\AbstractAdapter->get('img/.meta/jake-...')
#5 /Users/foobar/statamic-cms/vendor/laravel/framework/src/Illuminate/Cache/Repository.php(468): Statamic\\Assets\\Asset->Statamic\\Assets\\{closure}()
#6 /Users/foobar/statamic-cms/vendor/laravel/framework/src/Illuminate/Cache/CacheManager.php(453): Illuminate\\Cache\\Repository->rememberForever('asset-meta-asse...', Object(Closure))
#7 /Users/foobar/statamic-cms/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(361): Illuminate\\Cache\\CacheManager->__call('rememberForever', Array)
#8 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Assets/Asset.php(251): Illuminate\\Support\\Facades\\Facade::__callStatic('rememberForever', Array)
#9 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Assets/Asset.php(264): Statamic\\Assets\\Asset->meta()
#10 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Assets/Asset.php(229): Statamic\\Assets\\Asset->metaValue('last_modified')
#11 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Assets/Asset.php(592): Statamic\\Assets\\Asset->meta('last_modified')
#12 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Assets/Asset.php(1095): Statamic\\Assets\\Asset->lastModified()
#13 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Query/ResolveValue.php(52): Statamic\\Assets\\Asset->getQueryableValue('last_modified')
#14 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Query/ResolveValue.php(34): Statamic\\Query\\ResolveValue->getItemPartValue(Object(Statamic\\Assets\\Asset), 'last_modified')
#15 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Query/ResolveValue.php(22): Statamic\\Query\\ResolveValue->resolveItemPartValue(Object(Statamic\\Assets\\Asset), 'last_modified')
#16 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Stache/Indexes/Value.php(18): Statamic\\Query\\ResolveValue->__invoke(Object(Statamic\\Assets\\Asset), 'last_modified')
#17 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Stache/Indexes/Index.php(123): Statamic\\Stache\\Indexes\\Value->getItemValue(Object(Statamic\\Assets\\Asset))
#18 /Users/foobar/statamic-cms/vendor/laravel/framework/src/Illuminate/Collections/HigherOrderCollectionProxy.php(65): Statamic\\Stache\\Indexes\\Index->updateItem(Object(Statamic\\Assets\\Asset))
#19 /Users/foobar/statamic-cms/vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(259): Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(Statamic\\Stache\\Indexes\\Value), 'last_modified')
#20 /Users/foobar/statamic-cms/vendor/laravel/framework/src/Illuminate/Collections/HigherOrderCollectionProxy.php(64): Illuminate\\Support\\Collection->each(Object(Closure))
#21 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Stache/Stores/BasicStore.php(122): Illuminate\\Support\\HigherOrderCollectionProxy->__call('updateItem', Array)
#22 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Assets/AssetRepository.php(148): Statamic\\Stache\\Stores\\BasicStore->save(Object(Statamic\\Assets\\Asset))
#23 /Users/foobar/statamic-cms/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(361): Statamic\\Assets\\AssetRepository->save(Object(Statamic\\Assets\\Asset))
#24 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Assets/Asset.php(629): Illuminate\\Support\\Facades\\Facade::__callStatic('save', Array)
#25 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Assets/Asset.php(918): Statamic\\Assets\\Asset->save()
#26 /Users/foobar/statamic-cms/vendor/statamic/cms/src/Http/Controllers/CP/Assets/AssetsController.php(118): Statamic\\Assets\\Asset->upload(Object(Illuminate\\Http\\UploadedFile))
[...]

Environment

Environment
Application Name: REPLACE_ME
Laravel Version: 11.45.1
PHP Version: 8.3.17
Composer Version: 2.8.3
Environment: local
Debug Mode: ENABLED
URL: localhost
Maintenance Mode: OFF
Timezone: UTC
Locale: de

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: redis
Database: sqlite
Logs: stack / daily
Mail: smtp
Queue: redis
Session: redis

Sentry
Enabled: MISSING DSN
Environment: local
Laravel SDK Version: 4.10.1
PHP SDK Version: 4.10.0
Release: 33ccfde
Sample Rate Errors: 100%
Sample Rate Performance Monitoring: 1%
Sample Rate Profiling: 1%
Send Default PII: ENABLED

Statamic
Addons: 5
Sites: 2 (🇩🇪 Deutsch, 🇫🇷 Français)
Stache Watcher: Enabled
Static Caching: Disabled
Version: 5.59.0 PRO

Statamic Addons
cnj/seotamic: 5.0.0
teamnovu/graphql-breadcrumbs: 1.0.7
teamnovu/localize: 5.0.0
teamnovu/statamic-gql-swr-cache: 1.0.0
xndbogdan/statamic-bard-text-color: 5.1.1

Installation

Fresh statamic/statamic site via CLI

Additional details

Assets are stored on an S3.
Also, this issue is probably related to #8641 .

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions