{"record":{"id":"9e5bbfd33aa60155","repo":"basecamp/kamal","slug":"deploy-lock-found-run-kamal-lock-help-for-more","errorCode":null,"errorMessage":"Deploy lock found. Run 'kamal lock help' for more information","messagePattern":"Deploy lock found\\. Run 'kamal lock help' for more information","errorType":"exception","errorClass":"Kamal::Cli::LockError","httpStatus":null,"severity":"error","filePath":"lib/kamal/cli/base.rb","lineNumber":198,"sourceCode":"\n          say \"Retrying in #{interval}s (#{remaining}s remaining)...\", :magenta\n          sleep [ interval, remaining ].min\n        end\n      end\n\n      def release_lock\n        say \"Releasing the deploy lock...\", :magenta\n        execute_lock_release\n\n        KAMAL.holding_lock = false\n      end\n\n      def raise_if_locked\n        yield\n      rescue LockHeldError\n        say \"Deploy lock already in place!\", :red\n        puts capture_lock_status\n        raise LockError, \"Deploy lock found. Run 'kamal lock help' for more information\"\n      end\n\n      def execute_lock_acquire(message)\n        on(KAMAL.primary_host) { execute *KAMAL.lock.acquire(message, KAMAL.config.version), verbosity: :debug }\n      rescue SSHKit::Runner::ExecuteError => e\n        raise LockHeldError if e.message =~ /cannot create directory/\n        raise\n      end\n\n      def execute_lock_release\n        on(KAMAL.primary_host) { execute *KAMAL.lock.release, verbosity: :debug }\n      rescue SSHKit::Runner::ExecuteError => e\n        raise LockMissingError if e.message =~ /No such file or directory/\n        raise\n      end\n\n      def capture_lock_status\n        status = nil","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/cli/base.rb#L180-L216","documentation":"raise_if_locked wraps commands that must not proceed when a deploy lock exists (used when wait_when_locked is not configured, or for non-waiting commands). Acquiring the lock on the primary host fails with LockHeldError when the lock directory already exists (`cannot create directory`); Kamal prints 'Deploy lock already in place!' plus the captured status (holder message and version), then raises Kamal::Cli::LockError pointing at `kamal lock help`.","triggerScenarios":"Running any locking Kamal command (deploy, app stop/restart, proxy reboot, etc.) while the lock directory exists on the primary host — from a crashed previous deploy, a concurrent deploy, or a manual `kamal lock acquire`. Typical when no wait_when_locked is configured, so there is no waiting loop.","commonSituations":"CI deploy was cancelled mid-run leaving the lock; two developers deploying simultaneously; deploy process killed by OOM/timeout; previous deploy failed before its ensure-release ran.","solutions":["Inspect the holder: `kamal lock status` shows the message and version recorded when the lock was taken.","If no deploy is actually running, release it: `kamal lock release`, then retry your command.","If a deploy is legitimately in progress, wait for it to finish instead of force-releasing.","Add lock: wait_when_locked in config/deploy.yml so deploys queue rather than abort when overlapped."],"exampleFix":"# before\nkamal deploy   # -> Deploy lock found. Run 'kamal lock help' ...\n# after\nkamal lock status\nkamal lock release   # only if no deploy is really running\nkamal deploy\n# or make deploys queue instead of failing (config/deploy.yml):\nlock:\n  wait_when_locked:\n    interval: 5\n    timeout: 300","handlingStrategy":"try-catch","validationCode":"# Pre-check before any locking command:\nsystem(\"kamal lock status >/dev/null 2>&1\") # non-zero/locked output => inspect before deploy\n# Or in pipelines: gate on a clean status file you maintain after each release.","typeGuard":"def lock_free?(status_output)\n  status_output.strip.empty? || status_output.include?(\"No lock\")\nend","tryCatchPattern":"begin\n  Kamal::CLI::Deploy.new.perform\nrescue Kamal::Cli::LockError => e\n  status = `kamal lock status`\n  warn \"lock held:\\n#{status}\"\n  # release only after confirming no active deploy: kamal lock release\n  raise\nend","preventionTips":["Configure wait_when_locked so overlapping deploys queue instead of erroring.","Make CI releases idempotent and ensure a release step runs `kamal lock release` on failure paths.","Never remove the lock directory by hand on the primary host; use kamal lock release."],"tags":["kamal","deploy-lock","concurrency","cli"],"backgroundTag":"deploy-lock-held","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}