basecamp/kamal · error · RuntimeError
#{key} is present more than once
Error message
#{key} is present more than once What it means
Raised in Enpass#parse_result_and_take_secrets while folding the JSON returned by `enpass-cli -json -vault ... show ...`. Each item yields key = [title, label].compact.join('/'); when the same key appears a second time AND that key matches one of the requested secrets, kamal refuses to guess which password to use and raises. It is a duplicate-detection guard on top of an item/title/label tuple, not a general vault corruption error.
Source
Thrown at lib/kamal/secrets/adapters/enpass.rb:63
else
secret_titles << key
end
end.to_a
end
def parse_result_and_take_secrets(unparsed_result, secrets)
result = JSON.parse(unparsed_result)
result.reduce({}) do |secrets_with_passwords, item|
title = item["title"]
label = item["label"]
password = item["password"]
if title && password.present?
key = [ title, label ].compact.reject(&:empty?).join("/")
if secrets.include?(title) || secrets.include?(key)
raise RuntimeError, "#{key} is present more than once" if secrets_with_passwords[key]
secrets_with_passwords[key] = password
end
end
secrets_with_passwords
end
end
end
View on GitHub (pinned to eee0083b38)
Solutions
- Open Enpass and locate the duplicated title (search by the key shown in the error, e.g. 'API_KEY'); delete or rename the stale copy so the title is unique.
- If both entries are legitimate, rename one (e.g. API_KEY_OLD) and keep the requested name unique in the vault.
- If the duplicate is title-vs-label (two fields with the same label in one item), edit the item in Enpass so each labeled field is distinct, then re-run `kamal secrets pull`.
Example fix
# before: vault has two items titled DB_PASSWORD # kamal secrets pull # -> "DB_PASSWORD is present more than once" # after: rename one item in the Enpass app # DB_PASSWORD (keep, unique) # DB_PASSWORD_backup (renamed) kamal secrets pull
Defensive patterns
Strategy: validation
Validate before calling
def unique_secret_names?(names)
names.tally.values.all? { |count| count == 1 }
end
# Also validate the vault side before kamal does:
require "open3"
out, _err, st = Open3.capture3("enpass-cli", "-json", "-vault", "Primary", "show", *names)
if st.success?
keys = JSON.parse(out).map { |i| [i["title"], i["label"]].compact.reject(&:empty?).join("/") }
abort "Duplicate items in vault: #{keys.group_by(&:itself).select { |_, v| v.size > 1 }.keys.join(', ')}" unless keys.size == keys.uniq.size
end Try / catch
begin
adapter.fetch(names, from: "Primary", account: nil)
rescue RuntimeError => e
if e.message.end_with?("is present more than once")
raise "Duplicate Enpass item #{e.message}: rename the stale copy in the vault, then re-pull"
end
raise
end Prevention
- Keep one canonical item per secret title; move old values to clearly renamed backup entries.
- Audit for duplicate titles after vault imports/syncs (`enpass-cli` show -json and diff on title/label keys).
- Avoid reusing the same field label inside one item for multiple password fields.
When it happens
Trigger: adapter.fetch([...], from:, account:) where the vault contains two Enpass items with the same title and same (or empty) label, both with passwords, and that title (or title/label key) is in your requested secrets list; also one item exposing multiple fields with the identical label under the same title.
Common situations: Years-old vaults with 'Test', 'Login', or service-name duplicates created by sync/import; renaming an item but leaving a copy; items where the password lives under different fields and label collides after compact/reject of empty strings.
Related errors
- Enpass CLI is not installed
- Could not authenticate to Bitwarden Secrets Manager. Did you
- Bitwarden Secrets Manager CLI is not installed
- Failed to login to Doppler
- Could not read #{secrets} from Doppler
AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21).
Data as JSON: /api/errors/04ea7fe831246bca.
Report an issue: GitHub.