Skip to content

Fix plugin reinstall failure after deletion in Sandbox runtime#4044

Draft
agent-sandbox-automattic[bot] wants to merge 1 commit into
trunkfrom
ai/agent/stu-1931-1782979528
Draft

Fix plugin reinstall failure after deletion in Sandbox runtime#4044
agent-sandbox-automattic[bot] wants to merge 1 commit into
trunkfrom
ai/agent/stu-1931-1782979528

Conversation

@agent-sandbox-automattic

Copy link
Copy Markdown
Contributor

Related issues

Closes https://linear.app/a8c/issue/STU-1931

How AI was used in this PR

AI was used to investigate the root cause, design the fix, and write the code.

Proposed Changes

Fixes a bug where manually reinstalling a plugin (via zip upload) after deleting it through the WordPress Plugins admin screen would fail with:

The destination directory already exists and could not be removed.

The workaround was to restart the Studio site before reinstalling.

Root cause: In the Sandbox (PHP WASM) runtime, PHP runs as a persistent process whose internal stat/realpath caches persist across HTTP requests (unlike native PHP, where each request forks a fresh PHP process). After deleting a plugin in one request, PHP's cache can retain a stale "directory exists" result for the plugin path. On the next request (reinstalling the same plugin), WordPress calls is_dir() on the destination — the stale cache says it exists — then tries to delete it and gets an ENOENT-equivalent failure from the VFS layer, producing the error.

Fix: A new mu-plugin (0-clear-stat-cache-before-upgrade.php) hooks into WordPress's upgrader_pre_install filter and calls clearstatcache(true). This flushes both PHP's stat cache and its realpath cache immediately before any upgrade or install operation, ensuring is_dir() gets a fresh result from the real filesystem.

This is a no-op for the native PHP runtime (each request already starts with a clean process and empty caches).

Testing Instructions

  • Create a Studio site using the Sandbox PHP runtime
  • Navigate to wp-admin → Plugins → Add New Plugin → Upload Plugin, and install any plugin via zip (or install from the DotOrg directory)
  • Delete the plugin via the Plugins list
  • Upload/install the same plugin again
  • Before fix: the second install fails with "The destination directory already exists and could not be removed"
  • After fix: the second install succeeds

Pre-merge Checklist

  • Tested the fix against the reproduction steps described in STU-1931 (Sandbox runtime only; native PHP unaffected)
  • No UI/CSS changes — no visual review required
  • CI checks pass

Linear: STU-1931

Co-authored-by: wojtekn wojtek.naruniec@automattic.com

This PR was auto-generated by Agent Sandbox. Please review carefully before merging.

In the Sandbox (PHP WASM) runtime, PHP runs as a persistent process whose
internal stat/realpath caches persist across HTTP requests. After a plugin is
deleted via wp-admin, WordPress calls rmdir() which clears the stat-cache for
that exact path. However on the next request (reinstalling the same plugin) the
path may resolve differently (e.g. with/without trailing slash, via realpath)
and the stale cache entry causes is_dir() to return true for a directory that
no longer exists. WordPress then tries to delete it before installing, gets an
ENOENT-equivalent failure from the VFS, and returns the error "The destination
directory already exists and could not be removed."

Add a mu-plugin that hooks into upgrader_pre_install and calls
clearstatcache(true) to flush both the stat cache and the realpath cache before
any upgrade/install operation. This ensures WordPress gets an accurate
filesystem view and can proceed with the installation.

Co-authored-by: wojtekn <wojtek.naruniec@automattic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant