octobercms/october · error · ApplicationException

editor::lang.filesystem.error_deleting_directory

Error message

editor::lang.filesystem.error_deleting_directory

What it means

Thrown by editorMoveFilesOrDirectories after a directory's copyDirectory() SUCCEEDED but the original path contains '../', so the code refuses to delete the source (lines 224-229). Message: 'Error deleting the original directory :dir'. This is defense-in-depth: every source already passed validateFileSystemPath (which rejects '..'), so it is only reachable when $basePath itself was built with '../' segments — i.e., a custom extension supplying an unnormalized base path. Note the consequence: content now exists in BOTH places because the copy already ran.

Source

Thrown at modules/editor/traits/FileSystemFunctions.php:225

            if (is_file($originalFullPath)) {
                if (!@File::move($originalFullPath, $newFullPath)) {
                    throw new ApplicationException(Lang::get(
                        'editor::lang.filesystem.error_moving_file',
                        ['file' => $basename]
                    ));
                }
            }
            elseif (is_dir($originalFullPath)) {
                if (!@File::copyDirectory($originalFullPath, $newFullPath)) {
                    throw new ApplicationException(Lang::get(
                        'editor::lang.filesystem.error_moving_directory',
                        ['dir' => $basename]
                    ));
                }

                if (strpos($originalFullPath, '../') !== false) {
                    throw new ApplicationException(Lang::get(
                        'editor::lang.filesystem.error_deleting_directory',
                        ['dir' => $basename]
                    ));
                }

                if (strpos($originalFullPath, $safeDir) !== 0) {
                    throw new ApplicationException(Lang::get(
                        'editor::lang.filesystem.error_deleting_directory',
                        ['dir' => $basename]
                    ));
                }

                if (!@File::deleteDirectory($originalFullPath)) {
                    throw new ApplicationException(Lang::get(
                        'editor::lang.filesystem.error_deleting_directory',
                        ['dir' => $basename]
                    ));
                }

View on GitHub (pinned to b608633a7e)

Solutions

  1. Normalize the base path before calling editorMoveFilesOrDirectories: $basePath = realpath($basePath)
  2. If already hit, the destination copy is complete — delete the original directory manually after verifying the copy
  3. Audit custom editor extensions for '..' in their resolved base paths
  4. Prefer an absolute, symlink-free base path (or a symlink) instead of relative traversal segments

Example fix

// before (custom extension)
$base = base_path().'/../shared/assets'; // '..' leaks into originalFullPath
$this->editorMoveFilesOrDirectories($base, $src, $dst);

// after
$base = realpath(base_path().'/../shared/assets'); // normalized, no '../'
Defensive patterns

Strategy: validation

Validate before calling

// In custom extensions, before calling editorMoveFilesOrDirectories
$basePath = realpath($basePath);
if ($basePath === false || strpos($basePath, '../') !== false) {
    throw new \UnexpectedValueException('Base path must be a normalized absolute directory');
}

Prevention

When it happens

Trigger: A custom Editor\Classes\ExtensionBase subclass whose getAssetsPath() (or equivalent) returns a path containing '..' (e.g. base_path().'/../shared/assets'), combined with command_onAssetMove of a directory. Standard CMS/Tailor extensions, whose base paths are normalized theme directories, cannot trigger it.

Common situations: Bespoke editor extensions mounting asset roots outside the theme via relative '..' paths; refactors that assemble base paths from config without realpath(); copied example code for Tailor content extensions with sloppy path joins.

Related errors


AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21). Data as JSON: /api/errors/e3ee4a3a8359e123. Report an issue: GitHub.