{"record":{"id":"6e4e392f895f700a","repo":"coollabsio/coolify","slug":"the-following-file-is-a-file-on-the-server-but-yo","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"warning","filePath":"app/Models/LocalFileVolume.php","lineNumber":261,"sourceCode":"            $path = $workdir.$path;\n        }\n\n        // Validate and escape resolved path (may differ from fs_path if relative)\n        validateShellSafePath($path, 'storage path');\n        $escapedPath = escapeshellarg($path);\n\n        $isFile = instant_remote_process([\"test -f {$escapedPath} && echo OK || echo NOK\"], $server);\n        $isDir = instant_remote_process([\"test -d {$escapedPath} && echo OK || echo NOK\"], $server);\n        if ($isFile === 'OK' && $this->is_directory) {\n            if ($this->remoteFileExceedsLimit($escapedPath, $server)) {\n                $this->content = self::TOO_LARGE_PLACEHOLDER;\n            } else {\n                $this->content = instant_remote_process([\"cat {$escapedPath}\"], $server, false);\n            }\n            $this->is_directory = false;\n            $this->save();\n            FileStorageChanged::dispatch(data_get($server, 'team_id'));\n            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.');\n        } elseif ($isDir === 'OK' && ! $this->is_directory) {\n            if ($path === '/' || $path === '.' || $path === '..' || $path === '' || str($path)->isEmpty() || is_null($path)) {\n                $this->is_directory = true;\n                $this->save();\n                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.');\n            }\n            instant_remote_process([\n                \"rm -fr {$escapedPath}\",\n                \"touch {$escapedPath}\",\n            ], $server, false);\n            FileStorageChanged::dispatch(data_get($server, 'team_id'));\n        }\n        if ($isDir === 'NOK' && ! $this->is_directory) {\n            $chmod = data_get($this, 'chmod');\n            $chown = data_get($this, 'chown');\n            if ($content) {\n                $content = base64_encode($content);\n                $commands->push(\"echo '$content' | base64 -d | tee {$escapedPath} > /dev/null\");","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/coollabsio/coolify/blob/70b9acc42467278373e00de77abb40684e25b395/app/Models/LocalFileVolume.php#L243-L279","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","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.","Give the directory storage a different fs_path that does not collide with an existing file."],"exampleFix":"// before\n$fileVolume->is_directory = true;\n$fileVolume->saveStorageOnServer(); // throws: server path is a plain file\n\n// after — accept the self-heal, or clear the collision first\n// instant_remote_process(['rm '.escapeshellarg($path)], $server, false);\n$fileVolume->refresh(); // model was auto-corrected to is_directory=false\n$fileVolume->is_directory = true;\n$fileVolume->saveStorageOnServer();","handlingStrategy":"try-catch","validationCode":"// Pre-check server-side state before saving a directory-flagged storage\n$escapedPath = escapeshellarg($resolvedPath);\n$isFile = instant_remote_process([\"test -f {$escapedPath} && echo OK || echo NOK\"], $server);\nif ($isFile === 'OK' && $fileVolume->is_directory) {\n    // path collision: choose another fs_path or delete the file first\n}","typeGuard":null,"tryCatchPattern":"try {\n    $fileVolume->saveStorageOnServer();\n} catch (\\Exception $e) {\n    if (str_contains($e->getMessage(), 'you are trying to mark it as a directory')) {\n        // Model was auto-corrected to is_directory=false; refresh UI and re-save\n        $fileVolume->refresh();\n        return;\n    }\n    throw $e;\n}","preventionTips":["Pick unique fs_path values per storage definition; avoid two storages targeting the same path with different types.","Treat this exception as a reconcile notice, not a failure — always refresh() the model afterwards.","If a directory is required, clear the colliding file on the server before saving."],"tags":["coolify","file-storage","docker","remote-execution","state-mismatch"],"backgroundTag":"filesystem-type-mismatch","analyzedSha":"70b9acc42467278373e00de77abb40684e25b395","analyzedAt":"2026-08-17T01:41:01.313Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}