basecamp/kamal · error · RuntimeError

Enpass CLI is not installed

Error message

Enpass CLI is not installed

What it means

Raised by check_dependencies! in Kamal::Secrets::Adapters::Enpass when `enpass-cli version 2> /dev/null` fails. The adapter shells out to the third-party enpass-cli tool (not the Enpass desktop app) to read vault data, and Base#fetch probes for it before doing anything else. Note the probe uses the subcommand `version`, not a --version flag.

Source

Thrown at lib/kamal/secrets/adapters/enpass.rb:26

#
# Fetch only DB_PASSWORD from FooBar item
# `kamal secrets fetch --adapter enpass --from /Users/YOUR_USERNAME/Library/Containers/in.sinew.Enpass-Desktop/Data/Documents/Vaults/primary FooBar/DB_PASSWORD`
class Kamal::Secrets::Adapters::Enpass < Kamal::Secrets::Adapters::Base
  def requires_account?
    false
  end

  private
    def fetch_secrets(secrets, from:, account:, session:)
      secrets_titles = fetch_secret_titles(secrets)

      result = `enpass-cli -json -vault #{from.shellescape} show #{secrets_titles.map(&:shellescape).join(" ")}`.strip

      parse_result_and_take_secrets(result, secrets)
    end

    def check_dependencies!
      raise RuntimeError, "Enpass CLI is not installed" unless cli_installed?
    end

    def cli_installed?
      `enpass-cli version 2> /dev/null`
      $?.success?
    end

    def login(account)
      nil
    end

    def fetch_secret_titles(secrets)
      secrets.reduce(Set.new) do |secret_titles, secret|
        # Sometimes secrets contain a '/', when the intent is to fetch a single password for an item. Example: FooBar/DB_PASSWORD
        # Another case is, when the intent is to fetch all passwords for an item. Example: FooBar (and FooBar may have multiple different passwords)
        key, separator, value = secret.rpartition("/")
        if key.empty?
          secret_titles << value

View on GitHub (pinned to eee0083b38)

Solutions

  1. Install the enpass-cli tool (e.g. `cargo install enpass-cli` or your platform's release from the project README) and verify `enpass-cli version` succeeds.
  2. Ensure its install location (e.g. ~/.cargo/bin) is on PATH in the environment that runs kamal.
  3. In CI/containers, script the install step before invoking `kamal secrets pull`.
Defensive patterns

Strategy: validation

Validate before calling

require "open3"

def enpass_cli_installed?
  Open3.capture3("enpass-cli", "version")[2].success?
end

abort "Install enpass-cli (separate from the Enpass app) before pulling secrets" unless enpass_cli_installed?

Prevention

When it happens

Trigger: adapter.fetch(...) (e.g. `kamal secrets pull` with adapter enpass) on a machine lacking the enpass-cli binary on PATH, or where the binary exists but errors immediately (wrong arch, missing runtime).

Common situations: Assuming the Enpass desktop app is sufficient (it is not — the CLI is a separate community tool, typically installed via cargo/npm/package download); installing enpass-cli in a Rust cargo dir that is not on PATH for the shell/CI running kamal; macOS Gatekeeper blocking an unsigned binary.

Related errors


AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21). Data as JSON: /api/errors/0082224fe19ebb0d. Report an issue: GitHub.