{"record":{"id":"5e51cd6d2d57b8a2","repo":"basecamp/kamal","slug":"could-not-read-item-from-bitwarden","errorCode":null,"errorMessage":"Could not read #{item} from Bitwarden","messagePattern":"Could not read #(.+?) from Bitwarden","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"lib/kamal/secrets/adapters/bitwarden.rb","lineNumber":28,"sourceCode":"\n      if status[\"status\"] == \"locked\"\n        session = run_command(\"unlock --raw\", raw: true).presence\n        status = run_command(\"status\", session: session)\n      end\n\n      raise RuntimeError, \"Failed to login to and unlock Bitwarden\" unless status[\"status\"] == \"unlocked\"\n\n      run_command(\"sync\", session: session, raw: true)\n      raise RuntimeError, \"Failed to sync Bitwarden\" unless $?.success?\n\n      session\n    end\n\n    def fetch_secrets(secrets, from:, account:, session:)\n      {}.tap do |results|\n        items_fields(prefixed_secrets(secrets, from: from)).each do |item, fields|\n          item_json = run_command(\"get item #{item.shellescape}\", session: session, raw: true)\n          raise RuntimeError, \"Could not read #{item} from Bitwarden\" unless $?.success?\n          item_json = JSON.parse(item_json)\n          if fields.any?\n            results.merge! fetch_secrets_from_fields(fields, item, item_json)\n          elsif item_json.dig(\"login\", \"password\")\n            results[item] = item_json.dig(\"login\", \"password\")\n          elsif item_json[\"fields\"]&.any?\n            fields = item_json[\"fields\"].pluck(\"name\")\n            results.merge! fetch_secrets_from_fields(fields, item, item_json)\n          else\n            raise RuntimeError, \"Item #{item} is not a login type item and no fields were specified\"\n          end\n        end\n      end\n    end\n\n    def fetch_secrets_from_fields(fields, item, item_json)\n      fields.to_h do |field|\n        item_field = item_json[\"fields\"].find { |f| f[\"name\"] == field }","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/secrets/adapters/bitwarden.rb#L10-L46","documentation":"For each requested Bitwarden item the adapter runs `bw get item <name>`; a non-zero exit raises RuntimeError \"Could not read <item> from Bitwarden\". The command succeeded at the CLI level (session valid) but no item with that exact name/uuid was returned — typically a missing or unsynced item, or a name mismatch.","triggerScenarios":"Requesting secret RAILS_MASTER_KEY when the vault item is named myapp-master-key; item exists in a different organization/collection not accessible; item was created after the last bw sync; requesting with an id instead of the name kamal resolved.","commonSituations":"Renaming items in the Bitwarden web vault without updating deploy scripts; new teammate whose account lacks access to the organization holding the item; item created moments before fetch on another machine.","solutions":["Verify the item resolves: bw get item <name> in the same shell — if it errors, the name or access is wrong","Run bw sync to pull the latest vault, then retry the fetch","Use the item's exact name (or its UUID) in the kamal secrets fetch arguments, matching case","Confirm the logged-in account/organization can see the item in the Bitwarden web vault"],"exampleFix":"# before\nkamal secrets fetch -a bitwarden --account me@example.com MASTER_KEY\n# => RuntimeError: Could not read MASTER_KEY from Bitwarden\n\n# fix (terminal)\nbw sync\nbw get item myapp-master-key    # find the real name\nkamal secrets fetch -a bitwarden --account me@example.com myapp-master-key","handlingStrategy":"validation","validationCode":"items.each do |item|\n  ok = system(\"bw get item #{item.shellescape} > /dev/null 2>&1\")\n  warn \"bitwarden item `#{item}` not found/accessible — check name and bw sync\" unless ok\nend","typeGuard":"def bitwarden_item_exists?(name)\n  system(\"bw get item #{name.shellescape} > /dev/null 2>&1\")\nend","tryCatchPattern":"begin\n  secrets = adapter.fetch(names, account: account)\nrescue RuntimeError => e\n  if e.message.include?(\"from Bitwarden\")\n    names.each { |n| warn \"check item: bw get item #{n}\" unless system(\"bw get item #{n.shellescape} > /dev/null 2>&1\") }\n  end\n  raise\nend","preventionTips":["Run `bw sync` right after creating/renaming items so fetches see them","Prefer item UUIDs over display names in scripts to survive renames","Automate the item-exists pre-check in CI for a precise error before deploy"],"tags":["kamal","secrets","bitwarden","vault","item-not-found"],"backgroundTag":"vault-item-not-found","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}