coollabsio/coolify · warning · Exception

The following file is a file on the server, but you are tryi

Error message

The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.

What it means

Thrown by LocalFileVolume::saveStorageOnServer() (app/Models/LocalFileVolume.php:261) when the model is marked is_directory=true but the resolved path on the destination server already exists as a regular file (test -f returns OK). Coolify self-heals before throwing: it cats the file content (or stores a TOO_LARGE placeholder if it exceeds the size limit), flips is_directory to false, saves, and dispatches FileStorageChanged — then throws this Exception to tell the operator about the mismatch. So the error is informational; the model has already been reconciled to reality.

Source

Thrown at app/Models/LocalFileVolume.php:261

            $path = $workdir.$path;
        }

        // Validate and escape resolved path (may differ from fs_path if relative)
        validateShellSafePath($path, 'storage path');
        $escapedPath = escapeshellarg($path);

        $isFile = instant_remote_process(["test -f {$escapedPath} && echo OK || echo NOK"], $server);
        $isDir = instant_remote_process(["test -d {$escapedPath} && echo OK || echo NOK"], $server);
        if ($isFile === 'OK' && $this->is_directory) {
            if ($this->remoteFileExceedsLimit($escapedPath, $server)) {
                $this->content = self::TOO_LARGE_PLACEHOLDER;
            } else {
                $this->content = instant_remote_process(["cat {$escapedPath}"], $server, false);
            }
            $this->is_directory = false;
            $this->save();
            FileStorageChanged::dispatch(data_get($server, 'team_id'));
            throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
        } elseif ($isDir === 'OK' && ! $this->is_directory) {
            if ($path === '/' || $path === '.' || $path === '..' || $path === '' || str($path)->isEmpty() || is_null($path)) {
                $this->is_directory = true;
                $this->save();
                throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.');
            }
            instant_remote_process([
                "rm -fr {$escapedPath}",
                "touch {$escapedPath}",
            ], $server, false);
            FileStorageChanged::dispatch(data_get($server, 'team_id'));
        }
        if ($isDir === 'NOK' && ! $this->is_directory) {
            $chmod = data_get($this, 'chmod');
            $chown = data_get($this, 'chown');
            if ($content) {
                $content = base64_encode($content);
                $commands->push("echo '$content' | base64 -d | tee {$escapedPath} > /dev/null");

View on GitHub (pinned to 70b9acc424)

Solutions

  1. Nothing is broken — refresh the model/UI ($fileVolume->refresh()) and re-save; the record now correctly says is_directory=false with the file's content loaded.
  2. If you truly need a directory there, remove the file on the server (rm <path> via SSH or instant_remote_process) and save the storage again.
  3. Give the directory storage a different fs_path that does not collide with an existing file.

Example fix

// before
$fileVolume->is_directory = true;
$fileVolume->saveStorageOnServer(); // throws: server path is a plain file

// after — accept the self-heal, or clear the collision first
// instant_remote_process(['rm '.escapeshellarg($path)], $server, false);
$fileVolume->refresh(); // model was auto-corrected to is_directory=false
$fileVolume->is_directory = true;
$fileVolume->saveStorageOnServer();
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check server-side state before saving a directory-flagged storage
$escapedPath = escapeshellarg($resolvedPath);
$isFile = instant_remote_process(["test -f {$escapedPath} && echo OK || echo NOK"], $server);
if ($isFile === 'OK' && $fileVolume->is_directory) {
    // path collision: choose another fs_path or delete the file first
}

Try / catch

try {
    $fileVolume->saveStorageOnServer();
} catch (\Exception $e) {
    if (str_contains($e->getMessage(), 'you are trying to mark it as a directory')) {
        // Model was auto-corrected to is_directory=false; refresh UI and re-save
        $fileVolume->refresh();
        return;
    }
    throw $e;
}

Prevention

When it happens

Trigger: Toggling a file storage entry to 'directory' when fs_path already holds a plain file on the server; saving a storage definition whose path collides with a file created by the app or by a previous storage entry; two storage definitions pointing at the same path with different types.

Common situations: Editing the storage type dropdown on an existing mount without clearing the old file; apps that replace a mounted directory with a file (e.g. a bind-mounted config the app overwrites); copied/renamed services reusing fs_path values.

Related errors


AI-assisted analysis of coollabsio/coolify@70b9acc424 (2026-08-17). Data as JSON: /api/errors/6e4e392f895f700a. Report an issue: GitHub.