coollabsio/coolify · error · DeploymentException
Pre-deployment command: Could not find a valid container. Is
Error message
Pre-deployment command: Could not find a valid container. Is the container name correct?
What it means
Coolify throws this DeploymentException from run_pre_deployment_command() when a pre-deployment command is configured but resolveCommandContainer() cannot pick a container to run it in. Single-container apps always use their one running container; multi-container apps must have pre_deployment_command_container set, and it must prefix-match a running container named '{name}-{application-uuid}'. The job log right before the throw lists the containers that were actually available.
Source
Thrown at app/Jobs/ApplicationDeploymentJob.php:4763
return null;
}
private function run_pre_deployment_command()
{
if (empty($this->application->pre_deployment_command)) {
return;
}
$containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id);
if ($containers->count() == 0) {
$this->application_deployment_queue->addLogEntry('Pre-deployment command: No running containers found. Skipping.');
return;
}
$this->application_deployment_queue->addLogEntry('Executing pre-deployment command (see debug log for output/errors).');
$container = $this->resolveCommandContainer($containers, $this->application->pre_deployment_command_container, 'Pre-deployment');
if ($container === null) {
throw new DeploymentException('Pre-deployment command: Could not find a valid container. Is the container name correct?');
}
$containerName = data_get($container, 'Names');
if ($containerName) {
$this->validateContainerName($containerName);
}
// Security: pre_deployment_command is intentionally treated as arbitrary shell input.
// Users (team members with deployment access) need full shell flexibility to run commands
// like "php artisan migrate", "npm run build", etc. inside their own application containers.
// The trust boundary is at the application/team ownership level — only authenticated team
// members can set these commands, and execution is scoped to the application's own container.
// The single-quote escaping here prevents breaking out of the sh -c wrapper, but does not
// restrict the command itself. Container names are validated separately via validateContainerName().
// Newlines are normalized to spaces to prevent injection via SSH heredoc transport
// (matches the pattern used for health_check_command at line ~2824).
$preCommand = str_replace(["\r\n", "\r", "\n"], ' ', $this->application->pre_deployment_command);
$cmd = "sh -c '".str_replace("'", "'\''", $preCommand)."'";
$exec = "docker exec {$containerName} {$cmd}";View on GitHub (pinned to 70b9acc424)
Solutions
- Open the application's deployment command settings and set 'Pre-deployment command container' to the service name of exactly one container, without the -uuid suffix (e.g. 'app').
- Read the deployment debug log line 'Available: ...' — it lists the exact running container names Coolify sees; copy the prefix before the -uuid part.
- Verify on the server with docker ps that the intended container is running and belongs to the same application (and pull request) being deployed.
- If the container list is stale or contains leftovers from old deploys, remove the orphaned containers or redeploy so status is refreshed.
Example fix
// before: command set, container never selected for a multi-container app
$application->pre_deployment_command = 'php artisan migrate';
$application->pre_deployment_command_container = null;
// after: pin the command to one service name (job appends '-{uuid}' itself)
$application->pre_deployment_command = 'php artisan migrate';
$application->pre_deployment_command_container = 'app';
$application->save(); Defensive patterns
Strategy: validation
Validate before calling
// Before enabling/saving a pre-deployment command, confirm the target resolves
$containers = getCurrentApplicationContainerStatus($server, $application->id, $pullRequestId);
$names = $containers->pluck('Names');
if ($containers->count() === 0) {
// no running containers: command will be skipped, not thrown — decide if acceptable
}
if ($containers->count() > 1) {
$prefix = ($application->pre_deployment_command_container ?? '') . '-' . $application->uuid;
if (blank($application->pre_deployment_command_container)
|| ! $names->contains(fn ($n) => str_starts_with($n, $prefix))) {
// block: 'set pre_deployment_command_container to one of: ' . $names->implode(', ')
}
} Try / catch
catch (DeploymentException $e) { if (str_starts_with($e->getMessage(), 'Pre-deployment command:')) { surface as configuration error with the logged 'Available:' container list; do not retry; } else { throw $e; } } Prevention
- Whenever the app has or may have multiple containers, always set the command container field to a stable service name (no -uuid suffix).
- Keep compose service names stable across releases; if renamed, update pre/post deployment command container fields in the same change.
- After deployment failures, read the 'Available: ...' debug log line — it is the exact match set.
When it happens
Trigger: Application has 2+ running containers (scaling, extra compose services, sidecars) and pre_deployment_command_container is empty — resolveCommandContainer logs 'Multiple containers found but no container name specified' and returns null; or the configured name does not prefix-match any running container ('Container X not found. Available: ...'); or the target container exited/crashed before this step, since getCurrentApplicationContainerStatus only returns running containers for this application id and pull_request_id.
Common situations: Scaling an app or adding a sidecar service to docker-compose and leaving the container field blank; renaming the compose service after configuring the command so the old name no longer exists; entering the full container name including the -uuid suffix instead of just the service name; PR deployments where the matching PR container does not exist.
Related errors
- Post-deployment command: Could not find a valid container. I
- ScheduledTaskJob failed: No valid container was found. Is th
- 69420
- Command execution failed (exit code {$process_result->exitCo
- Invalid dockerfile_target_build: contains forbidden characte
AI-assisted analysis of coollabsio/coolify@70b9acc424 (2026-08-17).
Data as JSON: /api/errors/39d0b863c34f11a2.
Report an issue: GitHub.