{"record":{"id":"5ba6101e4f13265b","repo":"basecamp/kamal","slug":"could-not-find-the-following-secrets-in-passbolt","errorCode":null,"errorMessage":"Could not find the following secrets in Passbolt: #{missing_secrets.join(\", \")}","messagePattern":"Could not find the following secrets in Passbolt: #(.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"lib/kamal/secrets/adapters/passbolt.rb","lineNumber":55,"sourceCode":"            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 = []\n\n      # first get all top-level folders\n      parent_folders = folder_paths.map(&:first).uniq\n      filter_condition = \"--filter '#{parent_folders.map { |name| \"Name == #{name.shellescape.inspect}\" }.join(\" || \")}'\"","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/secrets/adapters/passbolt.rb#L37-L73","documentation":"After the passbolt CLI successfully returns a JSON resource list, the adapter compares the requested secret names against each item's \"name\" field (passbolt.rb:55). This error fires when one or more requested names are absent from the results, and the message lists them. The CLI worked; the name/folder combination you referenced simply does not match any readable resource.","triggerScenarios":"A secret reference like `passbolt/folder/SUBFOLDER/SECRET_NAME` in Kamal config where SECRET_NAME does not exist at that path, exists under a different folder or at root, is misspelled or has different casing, or is not shared with the Passbolt user the CLI authenticates as (unshared resources are simply absent from `list resources` output).","commonSituations":"Typo or wrong case in the secret name; the secret was moved to another folder but deploy.yml still references the old path; a root-level secret referenced with a folder prefix or vice versa; Passbolt permissions not granted to the CLI user or its group; trailing whitespace in the resource name.","solutions":["List what the CLI actually sees: `passbolt list resources --column name --json` (add `--folder <id>` for folder scoping) and copy the exact name.","Correct the reference in deploy.yml so the name and folder path match Passbolt exactly; names are case-sensitive.","In the Passbolt UI, confirm the resource is shared with the user whose GPG key the CLI uses.","If the secret lives at root, reference it without folder segments, or move it into the folder the config expects."],"exampleFix":"// before\n# deploy.yml\nsecrets:\n  - DB_PASSWORD=passbolt/infra/prod/db_password   # wrong folder path\n\n// after\nsecrets:\n  - DB_PASSWORD=passbolt/infra/db_password        # exact Name shown by `passbolt list resources`","handlingStrategy":"validation","validationCode":"# Verify every referenced secret exists before deploying\nrequired = %w[db_password api_token]\navailable = JSON.parse(`passbolt list resources --json`).map { |r| r[\"name\"] }\nmissing = required - available\nabort \"Missing in Passbolt: #{missing.join(', ')}\" if missing.any?","typeGuard":null,"tryCatchPattern":"begin\n  # task resolving passbolt/* secrets\nrescue RuntimeError => e\n  if e.message =~ /Could not find the following secrets in Passbolt/\n    abort \"#{e.message} — cross-check `passbolt list resources --column name --json`\"\n  else\n    raise\n  end\nend","preventionTips":["Copy secret names from `passbolt list resources` output, never from memory","Keep names in Passbolt and deploy.yml under one review process so renames stay in sync","After moving a resource between folders, grep deploy.yml for stale paths","Names are case-sensitive — review casing in references"],"tags":["passbolt","kamal","secrets","not-found","name-mismatch"],"backgroundTag":"secret-not-found","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}