coollabsio/coolify · error · RuntimeException

Invalid dockerfile_target_build: contains forbidden characte

Error message

Invalid dockerfile_target_build: contains forbidden characters.

What it means

During deployment, ApplicationDeploymentJob interpolates application->dockerfile_target_build into the docker build --target argument. Before doing so it validates the value against ValidationPatterns::DOCKER_TARGET_PATTERN (/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/): it must start alphanumeric and contain only letters, digits, dots, hyphens, underscores. Anything else — leading . or -, spaces, $, quotes, unicode — throws, protecting the shell command from injection.

Source

Thrown at app/Jobs/ApplicationDeploymentJob.php:353

                        if (preg_match('/-(\d{12})/', $containerName)) {
                            continue;
                        }
                        $containerIp = data_get($container, 'IPv4Address');
                        if ($containerName && $containerIp) {
                            $containerIp = str($containerIp)->before('/');
                            $ips->put($containerName, $containerIp->value());
                        }
                    }
                }
                $this->addHosts = $ips->map(function ($ip, $name) {
                    return "--add-host $name:$ip";
                })->implode(' ');
            }

            if ($this->application->dockerfile_target_build) {
                $target = $this->application->dockerfile_target_build;
                if (! preg_match(ValidationPatterns::DOCKER_TARGET_PATTERN, $target)) {
                    throw new \RuntimeException('Invalid dockerfile_target_build: contains forbidden characters.');
                }
                $this->buildTarget = " --target {$target} ";
            }

            // Check custom port
            ['repository' => $this->customRepository, 'port' => $this->customPort] = $this->application->customRepository();

            if (data_get($this->application, 'settings.is_build_server_enabled')) {
                $teamId = data_get($this->application, 'environment.project.team.id');
                $buildServers = Server::buildServers($teamId)->get();
                if ($buildServers->count() === 0) {
                    $this->application_deployment_queue->addLogEntry('No suitable build server found. Using the deployment server.');
                    $this->build_server = $this->server;
                } else {
                    $this->build_server = $buildServers->random();
                    $this->application_deployment_queue->build_server_id = $this->build_server->id;
                    $this->application_deployment_queue->addLogEntry("Found a suitable build server ({$this->build_server->name}).");
                    $this->use_build_server = true;

View on GitHub (pinned to 70b9acc424)

Solutions

  1. Set the Build Target field to a plain stage name that starts with a letter or digit, e.g. 'builder' or 'production' (letters, digits, . _ - only after the first char).
  2. Rename the corresponding stage in your Dockerfile to match the allowed pattern.
  3. Clear the field entirely if you do not need multi-stage targeting.
  4. If storing via API, apply ValidationPatterns::dockerTargetRules() on save so it fails at input time, not deploy time.

Example fix

# before: invalid build target stored on the application
# Dockerfile stage: FROM node:20 AS builder prod
dockerfile_target_build: 'builder prod'

# after: rename the stage and use it verbatim
# Dockerfile: FROM node:20 AS builder-prod
dockerfile_target_build: 'builder-prod'
Defensive patterns

Strategy: validation

Validate before calling

// Validate on save (UI/API), not at deploy time
$validated = $request->validate([
    'dockerfile_target_build' => ValidationPatterns::dockerTargetRules(), // nullable|string|max:128|regex:/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/
]);

Type guard

function isValidBuildTarget(?string $target): bool
{
    return blank($target) || preg_match(\App\Support\ValidationPatterns::DOCKER_TARGET_PATTERN, $target) === 1;
}

Prevention

When it happens

Trigger: Deploying an application whose 'Build Target' (dockerfile_target_build) field holds e.g. '.prod', '-builder', 'builder stage', 'prod$(whoami)', or any value copied with a space/quote; the field was set via UI or API without passing the same regex rule.

Common situations: Copy-pasting a stage name with whitespace; using shell-style variable names like $TARGET; older records saved before this validation existed now failing on redeploy.

Understand the failure class

Related errors


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