{"record":{"id":"d3fdd8614f30262d","repo":"basecamp/kamal","slug":"item-item-is-not-a-login-type-item-and-no-field","errorCode":null,"errorMessage":"Item #{item} is not a login type item and no fields were specified","messagePattern":"Item #(.+?) is not a login type item and no fields were specified","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"lib/kamal/secrets/adapters/bitwarden.rb","lineNumber":38,"sourceCode":"\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 }\n        raise RuntimeError, \"Could not find field #{field} in item #{item} in Bitwarden\" unless item_field\n        value = item_field[\"value\"]\n        [ \"#{item}/#{field}\", value ]\n      end\n    end\n\n    def items_fields(secrets)\n      {}.tap do |items|\n        secrets.each do |secret|\n          item, field = secret.split(\"/\")","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/secrets/adapters/bitwarden.rb#L20-L56","documentation":"When a Bitwarden secret is requested as a bare item name (no \"/field\" suffix), the adapter falls back to the item's login.password; if the item has no login.password and no custom fields at all, it raises RuntimeError. Non-login item types (secure notes, identities, cards) hit this unless a field is specified.","triggerScenarios":"Requesting a secure-note or identity item without a field: kamal secrets fetch -a bitwarden my-note (no /field); an item whose login has an empty password; an item of unknown type with zero custom fields.","commonSituations":"Storing a master key or API key as a Secure Note (natural choice) instead of a login item; migrating items between types; empty placeholder items created by automation.","solutions":["Request the specific custom field: use my-note/fieldName (the adapter then reads item_json[\"fields\"]) instead of the bare name","Or convert/store the value in a login-type item so login.password fallback works","Or add a custom field (e.g. named value) to the item and fetch item/value"],"exampleFix":"# before\nkamal secrets fetch -a bitwarden --account me@example.com my-api-key\n# item is a secure note => RuntimeError: Item my-api-key is not a login type item...\n\n# after (add a custom field \"value\" to the item in Bitwarden, then)\nkamal secrets fetch -a bitwarden --account me@example.com my-api-key/value","handlingStrategy":"validation","validationCode":"# Non-login items must be requested with an explicit /field\nname = \"my-api-key\"\njson = JSON.parse(`bw get item #{name.shellescape}`)\nabort \"#{name} has no login.password and no fields — request as #{name}/<field>\" if json.dig(\"login\", \"password\").nil? && json[\"fields\"].to_a.empty?","typeGuard":"def bitwarden_bare_fetchable?(item_json)\n  !item_json.dig(\"login\", \"password\").nil? || item_json[\"fields\"].to_a.any?\nend","tryCatchPattern":"begin\n  adapter.fetch([name], account: account)\nrescue RuntimeError => e\n  if e.message.include?(\"not a login type item\")\n    abort \"request `#{name}/<field>` instead — see `bw get item #{name}` for available fields\"\n  end\n  raise\nend","preventionTips":["Standardize on login-type items or explicit item/field refs for values fetched by kamal","Document your vault convention (e.g. every deploy secret item has a `value` custom field) so bare fetches never hit non-login items"],"tags":["kamal","secrets","bitwarden","vault","item-type"],"backgroundTag":"vault-item-schema-mismatch","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}