Environment
- Kirby: 5.3.2
- PHP: 8.2
- Multilingual: yes (EN default, DE, ZH)
- OS: macOS 15
What happened
Using a file.create:after hook that calls $file->changeName($newBase) to auto-rename uploaded files.
Two related bugs appear:
Bug 1 — changeName() leaves a UUID-only stub at the old filename
After calling changeName(), the renamed file and its sidecar are created correctly at the new path. However, a UUID-only stub (22 bytes, Uuid: <originalUUID>) is left behind at the original sidecar path, with no corresponding media file.
Steps to reproduce:
- Upload
photo.jpg to a page in a multilingual site
- In a
file.create:after hook, call $file->changeName('newname')
- Inspect the page's content folder
Expected:
newname.jpg ✓
newname.jpg.en.txt ✓ (with full content)
photo.jpg.en.txt — deleted
Actual:
newname.jpg ✓
newname.jpg.en.txt ✓ (with full content, new UUID)
photo.jpg.en.txt still exists — contains only Uuid: <originalUUID> (22 bytes)
Since photo.jpg no longer exists, Kirby's file collection for the page encounters a sidecar with no corresponding media file, causing errors when rendering the page.
Bug 2 — Orphaned sidecar misidentified as page content; Panel creates wrong _changes draft
When photo.jpg.en.txt (the stub from Bug 1) survives after the rename, and the user later opens the page in the Panel, Kirby's content scanner cannot find a corresponding photo.jpg media file. It therefore misidentifies the orphaned sidecar as the page content file.
The Panel then:
- Creates
_changes/photo.jpg.en.txt as a draft — containing the actual page content (Title, UUID matching the page, Page-layout blocks, etc.) rather than file metadata
- This draft persists across uploads and can be published, recreating the orphan in the main content folder with the page's UUID embedded
This means any subsequent cleanup of photo.jpg.en.txt from the main folder may be undone when the Panel publishes the stale _changes draft.
Notes
- Calling
update() on $file before changeName() returns a new File object (immutable model) — the changeName() call must use this updated object or Kirby throws "Storage for the file is immutable and cannot be moved."
- The UUID stub left by
changeName() has the original UUID (pjsl3eeauhp4j5it), while the new sidecar gets a new UUID (1mdypinsdsbkv5iy). Content saved before the rename that references the old UUID via file://pjsl3eeauhp4j5it will therefore be broken regardless of the stub cleanup.
rename() (deprecated) may have had the same behaviour; confirmed on changeName() in 5.3.2.
Environment
What happened
Using a
file.create:afterhook that calls$file->changeName($newBase)to auto-rename uploaded files.Two related bugs appear:
Bug 1 —
changeName()leaves a UUID-only stub at the old filenameAfter calling
changeName(), the renamed file and its sidecar are created correctly at the new path. However, a UUID-only stub (22 bytes,Uuid: <originalUUID>) is left behind at the original sidecar path, with no corresponding media file.Steps to reproduce:
photo.jpgto a page in a multilingual sitefile.create:afterhook, call$file->changeName('newname')Expected:
newname.jpg✓newname.jpg.en.txt✓ (with full content)photo.jpg.en.txt— deletedActual:
newname.jpg✓newname.jpg.en.txt✓ (with full content, new UUID)photo.jpg.en.txtstill exists — contains onlyUuid: <originalUUID>(22 bytes)Since
photo.jpgno longer exists, Kirby's file collection for the page encounters a sidecar with no corresponding media file, causing errors when rendering the page.Bug 2 — Orphaned sidecar misidentified as page content; Panel creates wrong
_changesdraftWhen
photo.jpg.en.txt(the stub from Bug 1) survives after the rename, and the user later opens the page in the Panel, Kirby's content scanner cannot find a correspondingphoto.jpgmedia file. It therefore misidentifies the orphaned sidecar as the page content file.The Panel then:
_changes/photo.jpg.en.txtas a draft — containing the actual page content (Title, UUID matching the page, Page-layout blocks, etc.) rather than file metadataThis means any subsequent cleanup of
photo.jpg.en.txtfrom the main folder may be undone when the Panel publishes the stale_changesdraft.Notes
update()on$filebeforechangeName()returns a new File object (immutable model) — thechangeName()call must use this updated object or Kirby throws "Storage for the file is immutable and cannot be moved."changeName()has the original UUID (pjsl3eeauhp4j5it), while the new sidecar gets a new UUID (1mdypinsdsbkv5iy). Content saved before the rename that references the old UUID viafile://pjsl3eeauhp4j5itwill therefore be broken regardless of the stub cleanup.rename()(deprecated) may have had the same behaviour; confirmed onchangeName()in 5.3.2.