{"record":{"id":"dd5930214dbdfc15","repo":"basecamp/kamal","slug":"could-not-read-secrets-from-passbolt","errorCode":null,"errorMessage":"Could not read #{secrets} from Passbolt","messagePattern":"Could not read #(.+?) from Passbolt","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"lib/kamal/secrets/adapters/passbolt.rb","lineNumber":51,"sourceCode":"\n          folder_path.each do |folder_name|\n            current_path << folder_name\n            matching_folders = folders.select { |f| get_folder_path(f, folders) == current_path.join(\"/\") }\n            current_folder = matching_folders.first if matching_folders.any?\n          end\n\n          if current_folder\n            filter_conditions << \"(Name == #{secret_name.shellescape.inspect} && FolderParentID == #{current_folder[\"id\"].shellescape.inspect})\"\n          end\n        else\n          # for root level secrets (no folders)\n          filter_conditions << \"Name == #{secret_name.shellescape.inspect}\"\n        end\n      end\n\n      filter_condition = filter_conditions.any? ? \"--filter '#{filter_conditions.join(\" || \")}'\" : \"\"\n      items = `passbolt list resources #{filter_condition} #{folders.map { |item| \"--folder #{item[\"id\"].to_s.shellescape}\" }.join(\" \")} --column name --column password --json`\n      raise RuntimeError, \"Could not read #{secrets} from Passbolt\" unless $?.success?\n      items = JSON.parse(items)\n      found_names = items.map { |item| item[\"name\"] }\n      missing_secrets = secret_names - found_names\n      raise RuntimeError, \"Could not find the following secrets in Passbolt: #{missing_secrets.join(\", \")}\" if missing_secrets.any?\n\n      items.to_h { |item| [ item[\"name\"], item[\"password\"] ] }\n    end\n\n    def secrets_get_folders(secrets)\n      # extract all folder paths (both parent and nested)\n      folder_paths = secrets\n        .select { |s| s.include?(\"/\") }\n        .map { |s| s.split(\"/\")[0..-2] } # get all parts except the secret name\n        .uniq\n\n      return [] if folder_paths.empty?\n\n      all_folders = []","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/secrets/adapters/passbolt.rb#L33-L69","documentation":"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).","triggerScenarios":"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.","commonSituations":"`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.","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."],"exampleFix":"// before\n# deploy.yml\nsecrets:\n  - DB_PASSWORD=passbolt/infra/pg\n# kamal deploy -> RuntimeError: Could to read [...] from Passbolt (opaque)\n\n// after\n# surface the CLI's real error first, fix auth/config, then re-run\n$ passbolt list resources --column name --column password --json\necho \"exit=$?\"","handlingStrategy":"try-catch","validationCode":"# Preflight the CLI before any Kamal run that resolves passbolt/* secrets\n`passbolt list resources --json 2>/dev/null`\nabort('Passbolt CLI read failed — check auth/config') unless $?.success?","typeGuard":null,"tryCatchPattern":"begin\n  # any Kamal task that resolves passbolt/* secrets (CLI or Kamal::Command)\nrescue RuntimeError => e\n  if e.message =~ /Could not read .* from Passbolt/\n    abort \"#{e.message} — diagnose with: passbolt list resources --json\"\n  else\n    raise\n  end\nend","preventionTips":["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"],"tags":["passbolt","kamal","secrets","cli","process-exit"],"backgroundTag":"cli-command-failed","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}