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

  1. 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').
  2. Read the deployment debug log line 'Available: ...' — it lists the exact running container names Coolify sees; copy the prefix before the -uuid part.
  3. Verify on the server with docker ps that the intended container is running and belongs to the same application (and pull request) being deployed.
  4. 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

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


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