{"record":{"id":"0082224fe19ebb0d","repo":"basecamp/kamal","slug":"enpass-cli-is-not-installed","errorCode":null,"errorMessage":"Enpass CLI is not installed","messagePattern":"Enpass CLI is not installed","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"lib/kamal/secrets/adapters/enpass.rb","lineNumber":26,"sourceCode":"#\n# Fetch only DB_PASSWORD from FooBar item\n# `kamal secrets fetch --adapter enpass --from /Users/YOUR_USERNAME/Library/Containers/in.sinew.Enpass-Desktop/Data/Documents/Vaults/primary FooBar/DB_PASSWORD`\nclass Kamal::Secrets::Adapters::Enpass < Kamal::Secrets::Adapters::Base\n  def requires_account?\n    false\n  end\n\n  private\n    def fetch_secrets(secrets, from:, account:, session:)\n      secrets_titles = fetch_secret_titles(secrets)\n\n      result = `enpass-cli -json -vault #{from.shellescape} show #{secrets_titles.map(&:shellescape).join(\" \")}`.strip\n\n      parse_result_and_take_secrets(result, secrets)\n    end\n\n    def check_dependencies!\n      raise RuntimeError, \"Enpass CLI is not installed\" unless cli_installed?\n    end\n\n    def cli_installed?\n      `enpass-cli version 2> /dev/null`\n      $?.success?\n    end\n\n    def login(account)\n      nil\n    end\n\n    def fetch_secret_titles(secrets)\n      secrets.reduce(Set.new) do |secret_titles, secret|\n        # Sometimes secrets contain a '/', when the intent is to fetch a single password for an item. Example: FooBar/DB_PASSWORD\n        # Another case is, when the intent is to fetch all passwords for an item. Example: FooBar (and FooBar may have multiple different passwords)\n        key, separator, value = secret.rpartition(\"/\")\n        if key.empty?\n          secret_titles << value","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/secrets/adapters/enpass.rb#L8-L44","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["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.","Ensure its install location (e.g. ~/.cargo/bin) is on PATH in the environment that runs kamal.","In CI/containers, script the install step before invoking `kamal secrets pull`."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"require \"open3\"\n\ndef enpass_cli_installed?\n  Open3.capture3(\"enpass-cli\", \"version\")[2].success?\nend\n\nabort \"Install enpass-cli (separate from the Enpass app) before pulling secrets\" unless enpass_cli_installed?","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Distinguish the Enpass desktop app from the third-party enpass-cli tool; only the latter satisfies the adapter.","Verify `enpass-cli version` (subcommand, not --version) works in the deploy environment.","Script the CLI install for CI since Enpass GUI cannot be used headless."],"tags":["ruby","kamal","enpass","cli","dependency","path","secrets"],"backgroundTag":"cli-not-installed","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}