basecamp/kamal · error · ArgumentError

No secrets given to fetch

Error message

No secrets given to fetch

What it means

Raised in Passbolt#fetch_secrets as an ArgumentError (not RuntimeError, unlike sibling adapter errors) when the secrets array is empty after prefixed_secrets mapping. It is an input-validation guard: the passbolt adapter refuses to build its folder/name filter query for a zero-length request. Since Base#fetch always reaches fetch_secrets after dependency/login checks, this fires only when the caller passed no secret names at all.

Source

Thrown at lib/kamal/secrets/adapters/passbolt.rb:15

class Kamal::Secrets::Adapters::Passbolt < Kamal::Secrets::Adapters::Base
  def requires_account?
    false
  end

  private

    def login(*)
      `passbolt verify`
      raise RuntimeError, "Failed to login to Passbolt" unless $?.success?
    end

    def fetch_secrets(secrets, from:, **)
      secrets = prefixed_secrets(secrets, from: from)
      raise ArgumentError, "No secrets given to fetch" if secrets.empty?

      secret_names = secrets.collect { |s| s.split("/").last }
      folders = secrets_get_folders(secrets)

      # build filter conditions for each secret with its corresponding folder
      filter_conditions = []
      secrets.each do |secret|
        parts = secret.split("/")
        secret_name = parts.last

        if parts.size > 1
          # get the folder path without the secret name
          folder_path = parts[0..-2]

          # find the most nested folder for this path
          current_folder = nil
          current_path = []

View on GitHub (pinned to eee0083b38)

Solutions

  1. Define the secrets you need in your kamal configuration (secrets: [ "ITEM", ... ]) so the pull has at least one name.
  2. If your wrapper computes names dynamically, skip the fetch entirely when the list is empty instead of calling the adapter.
  3. Pass names explicitly: `kamal secrets pull RAILS_MASTER_KEY` (adapter-specific CLI usage) when no config list exists yet.

Example fix

# before
adapter.fetch([], from: "Team")   # -> ArgumentError: No secrets given to fetch

# after
adapter.fetch(["RAILS_MASTER_KEY"], from: "Team")
# or guard at the call site:
#   adapter.fetch(names, from: "Team") unless names.empty?
Defensive patterns

Strategy: validation

Validate before calling

def fetch_passbolt_secrets!(adapter, names, from:)
  raise ArgumentError, "No secrets requested — nothing to pull from Passbolt" if names.to_a.empty?
  adapter.fetch(names, from: from)
end

Type guard

def valid_secret_list?(names)
  names.is_a?(Array) && !names.empty? && names.all? { |n| n.is_a?(String) && !n.strip.empty? }
end

Try / catch

begin
  adapter.fetch(names, from: "Team")
rescue ArgumentError => e
  raise "Passbolt adapter needs at least one secret name; populate your secrets list" if e.message == "No secrets given to fetch"
  raise
end

Prevention

When it happens

Trigger: adapter.fetch([], from: ...) — e.g. `kamal secrets pull` invoked with no secrets configured/selected for the passbolt adapter (empty secrets list in deploy config, or an empty SECRETS env/argument evaluated before the call).

Common situations: Skeleton deploy.yml where the secrets: section is still empty but a secrets pull was triggered; scripts that compute the secret list dynamically and pass an empty array on first run; copy-paste from another adapter that tolerates empty lists.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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