coollabsio/coolify · error · RuntimeException
The directory backup workdir is unavailable.
Error message
The directory backup workdir is unavailable.
What it means
Thrown by ScheduledVolumeBackup::sourcePath() (app/Models/ScheduledVolumeBackup.php:178). For a directory LocalFileVolume whose fs_path is relative (starts with '.'), the real path is workdir-relative: sourcePath() must call workdir() on the owning resource obtained via targetResource() ($this->backupable?->resource). If that resource is null — the storage row outlived its application/service/database — or the resource class does not have a workdir() method, the path cannot be resolved and the RuntimeException fires.
Source
Thrown at app/Models/ScheduledVolumeBackup.php:178
}
public function sourcePath(): string
{
$target = $this->backupable;
if ($target instanceof LocalPersistentVolume) {
return filled($target->host_path) ? $target->host_path : $target->name;
}
if (! $target instanceof LocalFileVolume || ! $target->is_directory) {
throw new \RuntimeException('The backup target is not a directory or persistent volume.');
}
$path = str($target->fs_path);
if ($path->startsWith('.')) {
$resource = $this->targetResource();
if (! $resource || ! method_exists($resource, 'workdir')) {
throw new \RuntimeException('The directory backup workdir is unavailable.');
}
return $resource->workdir().$path->after('.')->toString();
}
return $path->toString();
}
}
View on GitHub (pinned to 70b9acc424)
Solutions
- Restore or re-create the owning resource so backupable->resource resolves, or re-attach the storage to a live resource.
- Prefer an absolute fs_path (e.g. /data/... ) for directory storages that get backup schedules — sourcePath() returns it directly without needing workdir().
- If the resource is gone for good, delete the orphaned storage and its schedule instead of leaving a backup that always fails.
Example fix
// before
$path = $backup->sourcePath(); // throws: relative dir path, owning resource gone
// after — ensure an owning resource exists, or store an absolute path
$resource = $backup->targetResource();
if ($resource === null || ! method_exists($resource, 'workdir')) {
// orphaned: clean up rather than retry forever
$backup->delete();
return;
}
$path = $backup->sourcePath();
// structural fix: use an absolute directory path when creating the storage
$fileVolume->fs_path = '/data/backups/dir'; // instead of './dir' Defensive patterns
Strategy: type-guard
Validate before calling
// Before relying on sourcePath(), ensure a relative directory path has a live owner with workdir()
$target = $backup->backupable;
if ($target instanceof \App\Models\LocalFileVolume && str($target->fs_path)->startsWith('.')) {
$resource = $target->resource;
if ($resource === null || ! method_exists($resource, 'workdir')) {
abort(422, 'Directory backup target has no owning resource — re-attach it or use an absolute path.');
}
}
$path = $backup->sourcePath(); Type guard
function hasResolvableWorkdir(\App\Models\ScheduledVolumeBackup $backup): bool
{
$target = $backup->backupable;
if (! ($target instanceof \App\Models\LocalFileVolume)) {
return true; // volumes resolve via host_path/name
}
if (! str($target->fs_path)->startsWith('.')) {
return true; // absolute path needs no workdir
}
$resource = $target->resource;
return $resource !== null && method_exists($resource, 'workdir');
} Try / catch
try {
$path = $backup->sourcePath();
} catch (\RuntimeException $e) {
if (str_contains($e->getMessage(), 'workdir is unavailable')) {
// owning resource deleted or lacks workdir(): delete the orphaned schedule or re-attach storage to a live resource
$backup->delete();
return;
}
throw $e;
} Prevention
- Prefer absolute fs_path values for directory storages that carry backup schedules — they skip workdir() resolution entirely.
- When deleting applications/services, cascade their file storages and backup schedules together so no orphaned relative paths remain.
- Health-check scheduled backups by verifying backupable->resource still exists before each run.
When it happens
Trigger: Running a directory backup where the LocalFileVolume's resource (application, service application, service database) was deleted but the volume/schedule rows remained, or the morphed resource type is a model without a workdir() method; combined with a relative fs_path like './data'.
Common situations: Partial cascades that delete the resource but leave file-storage rows; schedules attached to storages of exotic/custom resource types; data imported between instances where resource rows are missing.
Related errors
- The backup target is not a directory or persistent volume.
- The following file is a file on the server, but you are tryi
- The following file is a directory on the server, but you are
- Failed to store SSH key: {message}
- Failed to open lock file for SSH key: {$lockFile}
AI-assisted analysis of coollabsio/coolify@70b9acc424 (2026-08-17).
Data as JSON: /api/errors/af888869ce9f4ef1.
Report an issue: GitHub.