Troubleshooting
Start with pilum dry-run for the service. It prints every command Pilum would run, which answers most “why did it do that” questions. Add --debug to a real run to see each command’s working directory, timeout and environment.
Service Discovery
”No services found to deploy”
$ pilum deploy⚠ No services found to deployCauses:
- No
pilum.yamlfiles below the current directory. Pipeline commands search from where you run them, down to 4 directory levels. - Files named
pilum.ymlorservice.yaml. The file must be namedpilum.yaml. - The directory is excluded by
.gitignoreor.pilumignore. --only-changedfound no changed services, or--providerfiltered everything out.
Fix:
find . -maxdepth 5 -name pilum.yamlpilum listpilum list --no-gitignore # if a .gitignore pattern hides the serviceWith no service names, an empty result is a warning and exits 0. If you named services and none matched, the command fails with exit code 3 and suggests close names. See Ignore Files.
”has no matching recipe”
Error: service 'web' (recipe key 'fly-app') has no matching recipeCause: the service’s type doesn’t match a recipe key, and no recipe exists for its provider either. This usually means a custom type without the matching --recipe-path.
Fix: use one of the built-in types (pilum recipes), or pass the directory with your recipe:
pilum deploy web --recipe-path ./recipes --tag v1.2.0--recipe-path replaces the built-in recipes, so that directory must also contain any built-in recipes your other services use. See How Recipes Work.
Service only builds and pushes, never deploys
━━━ Step 1/3: build binary ━━━━━━ Step 2/3: build docker image ━━━━━━ Step 3/3: publish to registry ━━━Cause: the service has provider: gcp but no type, or a misspelled one. Pilum then falls back to the first GCP recipe alphabetically, gcp-artifact-registry-image, which builds and pushes an image and has no deploy step. pilum check only warns about it:
Checking service api (recipe: gcp)⚠ No recipe found for 'gcp' - did you mean 'npm'?✓ All services are validFix: set type explicitly:
name: apitype: gcp-cloud-runproject: my-projectregion: us-central1registry_name: servicestemplate: goValidation Errors
”recipe requires field ‘X’”
✗ error checking service api: recipe 'gcp-cloud-run' requires field 'registry_name': Artifact Registry repository name (bare name, e.g. "my-repo" — not a full host/path)Fix: add the field to pilum.yaml. pilum recipes <type> lists every required field. For template, the error explains that it names a Dockerfile in your project at _templates/<name>; pilum init can scaffold one.
”missing required field: provider”
✗ error checking service api: missing required field: providerCause: neither provider nor a recognized built-in type is set. Pilum infers provider only from built-in types, so a misspelled type (such as gcp-cloudrun) or a custom type also produces this.
Fix: correct the type, or set provider explicitly.
Nested field errors
Error: recipe 'homebrew' requires field 'homebrew.tap_url'Fix: dotted field names are nested keys:
name: my-tooltype: homebrewdescription: My CLI toollicense: Apache-2.0homebrew: project_url: https://github.com/org/my-tool tap_url: https://github.com/org/homebrew-tap token_env: HOMEBREW_TAP_TOKENBefore Any Step Runs
Docker daemon not running
✗ docker daemon is not running — start Docker and retry (...)✗ docker daemon did not respond within 10s — is Docker running?✗ docker is required but was not found in PATHCause: at least one step that will run calls docker, and Pilum checks the daemon before building anything.
Fix: start Docker Desktop (or the daemon) and retry. If you only need non-Docker steps, filter them, for example pilum deploy --only-tags deploy. Dry runs skip this check.
Deployment locked
✗ deployment locked by PID 12345 on ci-runner-7 (started 2026-10-07T10:00:00Z, command: deploy, services: [api worker]). Use --force to overrideExit code 7.
Cause: another deploy, build, publish, push or rollback in the same project holds .pilum/deploy.lock.
Fix: wait for it to finish. Pilum clears the lock itself if the holding process is dead or the lock is more than 1 hour old. If you are sure nothing is running (for example, a CI runner was killed on another machine, so Pilum can’t check its PID), override it:
pilum deploy --tag v1.2.0 --forceA FORCE environment variable also sets --force; see Environment variables.
”gcp-mig-container needs a unique —tag per release”
Error: service 'egress-proxy' validation failed: gcp-mig-container needs a unique --tag per release (got "latest"): templates are named <base>-<tag>, and reusing one would make the rollout a no-opCause: MIG releases create an instance template named <template_base>-<tag>. An empty tag or latest would reuse a template, so Pilum rejects it before building.
Fix: pass a unique tag such as a version or commit SHA:
pilum deploy egress-proxy --tag v1.4.2Tags are lowercased and ., _ and + become -, so v1.4.2 creates <template_base>-v1-4-2. The full name must fit in GCP’s 63-character limit. See GCP Managed Instance Group.
”Warming failed; continuing with cold builds”
⚠ Warming failed; continuing with cold buildsCause: a build-cache warming command failed, for example because a lockfile is out of date or a build.warm command is wrong.
What happens: nothing breaks. The builds still run, without the shared warm cache, and any real error shows up in the build step itself.
Fix: run the warm command shown in pilum dry-run by hand to see the error. To turn warming off, use --no-warm for one run, or build.warm: false for a service. See Build Cache Warming.
Build Failures
”command not found”
sh: go: command not foundCause: build.cmd runs through sh -c, and other steps call docker, gcloud, az, sam, npm or git directly. The tool isn’t installed or isn’t on the PATH Pilum inherits.
Fix: install the tool the step calls and make sure it’s on PATH:
which go docker gcloudBuild timeout
command timed outCause: the step ran longer than its timeout. Every built-in step sets its own timeout (300 seconds for builds), and a step’s timeout overrides --timeout. So pilum deploy --timeout 600 does not extend built-in steps.
Fix:
- Make the build faster: let build cache warming run, and reduce parallel pressure with
--max-workers. - Or copy the built-in recipes into a directory, raise that step’s
timeout, and deploy with--recipe-path:
steps: - name: build docker image execution_mode: root timeout: 900 tags: [build]- Run the build by hand to see where the time goes:
cd services/api && go build -o ./dist/app .Dockerfile not found
The build docker image step fails and Docker reports that the Dockerfile path (_templates/<template>) doesn’t exist.
Cause: Pilum doesn’t look for a Dockerfile in each service directory. The image step runs from the directory where you ran pilum:
docker build -t <image>:<tag> --build-arg SERVICE_NAME=<service path> -f ./_templates/<template> .The Dockerfile is _templates/<template>, relative to that directory, and the build context is that directory. The service’s path relative to it is passed as the SERVICE_NAME build argument, so one template can serve many services.
Fix:
- Run
pilumfrom the project root (the directory that contains_templates/). - Check that
_templates/<template>exists, where<template>is thetemplate:value inpilum.yaml. pilum initwrites_templates/<language>in the directory you run it from. If you ran it inside a service directory, move_templates/to the project root.
failed to compute cache key: "…/dist": not found
ERROR: failed to compute cache key: failed to calculate checksum of ref …::…: "/services/api/dist": not foundDocker usually also prints an easy-to-miss warning:
1 warning found: - CopyIgnoredFile: Attempting to Copy file "services/api/dist" that is excluded by .dockerignore (line N)Cause: the build binary step compiles into services/<name>/dist/ on the host, and the Dockerfile copies it with something like COPY ./services/<name>/dist .. If the repo’s .dockerignore contains **/dist, dist/ or any pattern matching that directory, Docker drops it from the build context even though it exists on disk.
Fix: remove the dist pattern from .dockerignore, or narrow it to the outputs you really want excluded (for example apps/web/dist) instead of a repo-wide **/dist.
.gitignore controls what git tracks; .dockerignore controls what Docker sends to the daemon. Any path a Dockerfile COPYs must not match .dockerignore.
Authentication Errors
GCP
ERROR: (gcloud.run.deploy) PERMISSION_DENIEDFix:
gcloud auth logingcloud auth configure-docker us-central1-docker.pkg.dev # your Artifact Registry hostgcloud config set project YOUR_PROJECT_IDIn CI, authenticate the runner’s service account before running Pilum. Pilum uses whatever credentials gcloud and docker already have.
AWS
Unable to locate credentialsFix:
aws configure# orexport AWS_ACCESS_KEY_ID=...export AWS_SECRET_ACCESS_KEY=...export AWS_REGION=us-east-1The aws-lambda recipe runs sam build and sam deploy, so the AWS SAM CLI must be installed too.
Azure
ERROR: Please run 'az login' to setup account.Fix:
az loginaz acr login --name YOUR_ACR_NAMEPush Failures
Registry access denied
denied: Permission "artifactregistry.repositories.uploadArtifacts" deniedFix:
- Configure Docker for the registry host:
gcloud auth configure-docker <region>-docker.pkg.devfor GCP,az acr login --name <registry>for Azure. - Check
registry_name. For GCP it is the bare Artifact Registry repository name, not a host or path; Pilum builds<region>-docker.pkg.dev/<project>/<registry_name>/<name>from it:
registry_name: services- Make sure the repository exists in that project and region. Pilum doesn’t create it.
Deploy Problems
Existing secrets or env vars disappeared after a Cloud Run deploy
Cause: Cloud Run deploys state env vars and secrets every time. When a service has none, Pilum passes --clear-env-vars and --clear-secrets, which remove whatever is set on the live service. The usual trigger is writing secrets or env_vars as a list:
# Wrong: a list is silently ignored, so the deploy clears all secretssecrets: - name: DATABASE_URL value: database-url:latestFix: use a map of NAME: value:
env_vars: LOG_LEVEL: infosecrets: DATABASE_URL: database-url:latest # secret-name:versionCheck with pilum dry-run: the deploy command should show --set-secrets, not --clear-secrets. Then redeploy to restore them. See Service Configuration.
Cloud Run service returns 403
Cause: Pilum deploys Cloud Run services with --no-allow-unauthenticated unless cloud_run.allow_unauthenticated: true is set.
Fix: for a public service:
cloud_run: allow_unauthenticated: trueDeploy reports success but nothing ran
Cause: a step with no command whose name matches no handler does nothing and counts as a success. This happens with custom recipes that use an unknown step name, and with execute job when job.execute_on_deploy is not true.
Fix: run pilum dry-run. Steps listed without a → command line are no-ops.
Rollback
”refusing to roll back without confirmation”
✗ refusing to roll back without confirmation; pass --yes to proceed non-interactivelyExit code 6.
Cause: rollback asks for confirmation, and there’s no terminal to ask on. Pilum treats a run as non-interactive when stdin isn’t a terminal or is /dev/null, when CI, GITHUB_ACTIONS, GITLAB_CI, CIRCLECI, JENKINS_URL or BUILDKITE is set, and in --json mode.
Fix: review the plan, then pass --yes:
pilum rollback api --dry-runpilum rollback api --yes“rollback is not supported”
✗ rollback is not supported for web (recipe cloudflare-pages); supported: Cloud Run services and jobs, GCP MIGsCause: rollback works only for gcp-cloud-run, gcp-cloud-run-from-image, gcp-cloud-run-job and gcp-mig-container.
Fix: for other targets, deploy the previous known-good tag:
pilum history -s webpilum deploy web --tag v1.1.0Traffic went back to the new revision
Cause: pilum rollback pins traffic to an older Cloud Run revision. The next pilum deploy runs route traffic to latest, which moves traffic to the new revision and resets any manual traffic split. That is intended: a deploy means “serve this”.
Fix: fix forward and deploy again, or roll back again after the deploy. See Rollback, Status & History.
Parallel Execution
Machine slows down or runs out of memory
Cause: too many builds at once. Pilum sizes build steps by CPU cores and memory, but its per-language memory estimates may be low for your builds.
Fix: cap the workers, or tell Pilum how much each build needs:
pilum deploy --max-workers 2 --tag v1.2.0build: resources: memory: 4096 # MB per build cpu: 4 # cores per buildOn Docker Desktop, Docker steps are sized against the Docker VM’s CPUs and memory. Give the VM more resources if image builds are slow.
Services interfere with each other
Cause: parallel steps write to the same files, for example a shared output directory.
Fix: run serially to confirm, then give each service its own output path:
pilum deploy --max-workers 1 --tag v1.2.0Unexpected Flag Values
Wrong tag, environment or provider with no flag set
Cause: Pilum reads environment variables named like its flags. TAG, ENV, PROVIDER, DEBUG, TIMEOUT, RETRIES, FORCE and SINCE set in your shell or CI act as defaults for those flags.
Fix: check with env | grep -E '^(TAG|ENV|PROVIDER|DEBUG|FORCE)=', unset the variable, or pass the flag explicitly. See CLI Commands.
Homebrew Issues
”push to tap” authentication fails
Cause: Pilum pushes the formula to the tap with git, using the token from the environment variable named by homebrew.token_env.
Fix: export that variable with a token that can push to the tap repository:
export HOMEBREW_TAP_TOKEN="ghp_xxxxx" # the name set in homebrew.token_envDebug Mode
pilum deploy api --debug --tag v1.2.0Prints, for each command:
- the command and its arguments
- the working directory and execution mode
- the timeout
- environment variables, with values of names ending in
_TOKEN,_SECRET,_KEY,_PASSWORDor_CREDENTIALredacted
--verbose streams each command’s output as it runs.
Getting Help
If the problem persists:
- Run
pilum dry-runand the failing command with--debug. - Search GitHub Issues.
- Open an issue with your Pilum version (
pilum --version), the full error, thepilum.yamlwith secrets removed, the recipetype, and the debug output.
Next Steps
- CLI Commands — Every command, flag and exit code
- How Recipes Work — Recipe lookup, steps and timeouts
- FAQ — Common questions