basecamp/kamal · error · RuntimeError
Could not read #{secrets} from Passbolt
Error message
Could not read #{secrets} from Passbolt What it means
Kamal's Passbolt secrets adapter reads secrets by shelling out to the passbolt CLI: `passbolt list resources <filter> <folders> --column name --column password --json`. This RuntimeError (passbolt.rb:51) is raised when that process exits non-zero ($?.success? is false), meaning the CLI itself failed before any secret name could be matched. It points to a CLI/session/server problem, not a wrong secret name (that produces the separate 'Could not find the following secrets' error).
Source
Thrown at lib/kamal/secrets/adapters/passbolt.rb:51
folder_path.each do |folder_name|
current_path << folder_name
matching_folders = folders.select { |f| get_folder_path(f, folders) == current_path.join("/") }
current_folder = matching_folders.first if matching_folders.any?
end
if current_folder
filter_conditions << "(Name == #{secret_name.shellescape.inspect} && FolderParentID == #{current_folder["id"].shellescape.inspect})"
end
else
# for root level secrets (no folders)
filter_conditions << "Name == #{secret_name.shellescape.inspect}"
end
end
filter_condition = filter_conditions.any? ? "--filter '#{filter_conditions.join(" || ")}'" : ""
items = `passbolt list resources #{filter_condition} #{folders.map { |item| "--folder #{item["id"].to_s.shellescape}" }.join(" ")} --column name --column password --json`
raise RuntimeError, "Could not read #{secrets} from Passbolt" unless $?.success?
items = JSON.parse(items)
found_names = items.map { |item| item["name"] }
missing_secrets = secret_names - found_names
raise RuntimeError, "Could not find the following secrets in Passbolt: #{missing_secrets.join(", ")}" if missing_secrets.any?
items.to_h { |item| [ item["name"], item["password"] ] }
end
def secrets_get_folders(secrets)
# extract all folder paths (both parent and nested)
folder_paths = secrets
.select { |s| s.include?("/") }
.map { |s| s.split("/")[0..-2] } # get all parts except the secret name
.uniq
return [] if folder_paths.empty?
all_folders = []View on GitHub (pinned to eee0083b38)
Solutions
- Run the exact command manually to surface the real error: `passbolt list resources --column name --column password --json`, and inspect stderr and the exit code.
- Re-run `passbolt configure` (server URL, private key path, key fingerprint), re-verify the server key, and confirm authentication succeeds.
- Verify network access from the machine running Kamal to the Passbolt API host, and that the API is up.
- Confirm the CLI config lives in the HOME of the same user/process that runs Kamal (CI shells and systemd units often differ).
- Upgrade or pin a passbolt CLI version whose `list resources` subcommand supports the filter/folder flags used by the adapter.
Example fix
// before # deploy.yml secrets: - DB_PASSWORD=passbolt/infra/pg # kamal deploy -> RuntimeError: Could to read [...] from Passbolt (opaque) // after # surface the CLI's real error first, fix auth/config, then re-run $ passbolt list resources --column name --column password --json echo "exit=$?"
Defensive patterns
Strategy: try-catch
Validate before calling
# Preflight the CLI before any Kamal run that resolves passbolt/* secrets
`passbolt list resources --json 2>/dev/null`
abort('Passbolt CLI read failed — check auth/config') unless $?.success? Try / catch
begin
# any Kamal task that resolves passbolt/* secrets (CLI or Kamal::Command)
rescue RuntimeError => e
if e.message =~ /Could not read .* from Passbolt/
abort "#{e.message} — diagnose with: passbolt list resources --json"
else
raise
end
end Prevention
- Run `passbolt list resources --json` as a CI preflight before kamal deploy
- Keep the CLI config (from `passbolt configure`) in the HOME of the user that runs Kamal
- Monitor Passbolt server availability and server-key rotation
- Pin a known-good passbolt CLI version in CI images
When it happens
Trigger: Any Kamal run that resolves passbolt secret references (e.g. `kamal secrets fetch`, or `kamal deploy` with `secrets: - FOO=passbolt/folder/NAME` in deploy.yml) while the backtick command fails: the CLI is not authenticated or its session expired, the Passbolt server is unreachable, the server URL in CLI config is wrong, the GPG private key is missing/invalid, or the installed CLI version rejects the flags used.
Common situations: `passbolt configure` was never run or points at the wrong server; the deploy box lost its GPG key or the server key rotated; CI runners lacking the CLI config under HOME; a passbolt CLI version whose `list resources` flags differ; Passbolt API down or blocked by a firewall.
Related errors
- Could not read folders from Passbolt
- Unknown secrets adapter: #{name}
- Could not read #{secrets} from AWS Secrets Manager
- Missing required option '--account'
- Failed to login to and unlock Bitwarden
AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21).
Data as JSON: /api/errors/dd5930214dbdfc15.
Report an issue: GitHub.