Skip to content

Static Cache Writer producing invalid HTML #14742

@JorisOrangeStudio

Description

@JorisOrangeStudio

Bug description

Credits to Claude on helping me to find this, hopefully it is all clear 😅

Statamic\StaticCaching\Cachers\Writer::write() opens cache files in mode c and fwrite the new content, but never truncates. So when a page is re-cached with content shorter than the file already on disk, the old bytes past the new content survive, producing a valid document followed by garbage after </html>.

// src/StaticCaching/Cachers/Writer.php
$handle = fopen($path, 'c');          // does NOT truncate
if (! flock($handle, LOCK_EX | LOCK_NB)) {
    return false;
}
fwrite($handle, $content);            // leaves any bytes past $content

With background_recache on (default), saving an entry overwrites the file in place rather than deleting it, so any edit that shrinks a page leaves a stale tail. It's "sticky": the file is never shrunk, so its size stays pinned at the largest version ever written. Small edits only shorten the leftover — it clears only when a render exceeds the whole on-disk length, or the file is deleted.

How to reproduce

  1. Full static caching (STATAMIC_STATIC_CACHING_STRATEGY=full), background_recache on.
  2. Cache a page: the file ends cleanly at </html>.
  3. Edit an entry on that page so it renders fewer bytes; save.
  4. The cached .html now has leftover bytes from the previous render after </html>.

Logs

Environment

Laravel Version: 12.58.0
PHP Version: 8.4.21
Static Caching: full, background_recache enabled
Multisite: yes
Statamic Version: 6.16.0 PRO

Installation

Fresh statamic/statamic site via CLI

Additional details

Image Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions