diff --git a/beetsplug/beatport.py b/beetsplug/beatport.py
index 8ef356fe8..c3933ed73 100644
--- a/beetsplug/beatport.py
+++ b/beetsplug/beatport.py
@@ -150,9 +150,11 @@ class BeatportClient(object):
         :rtype:                 :py:class:`BeatportRelease`
         """
         response = self._get('/catalog/3/releases', id=beatport_id)
-        release = BeatportRelease(response[0])
-        release.tracks = self.get_release_tracks(beatport_id)
-        return release
+        if response:
+            release = BeatportRelease(response[0])
+            release.tracks = self.get_release_tracks(beatport_id)
+            return release
+        return None
 
     def get_release_tracks(self, beatport_id):
         """ Get all tracks for a given release.
@@ -261,10 +263,10 @@ class BeatportTrack(BeatportObject):
             self.musical_key = six.text_type(data['key'].get('shortName'))
 
         # Use 'subgenre' and if not present, 'genre' as a fallback.
-        if 'subGenres' in data:
+        if data.get('subGenres'):
             self.genre = six.text_type(data['subGenres'][0].get('name'))
-            if not self.genre and 'genres' in data:
-                self.genre = six.text_type(data['genres'][0].get('name'))
+        elif data.get('genres'):
+            self.genre = six.text_type(data['genres'][0].get('name'))
 
 
 class BeatportPlugin(BeetsPlugin):
@@ -375,27 +377,31 @@ class BeatportPlugin(BeetsPlugin):
 
     def album_for_id(self, release_id):
         """Fetches a release by its Beatport ID and returns an AlbumInfo object
-        or None if the release is not found.
+        or None if the query is not a valid ID or release is not found.
         """
         self._log.debug(u'Searching for release {0}', release_id)
         match = re.search(r'(^|beatport\.com/release/.+/)(\d+)$', release_id)
         if not match:
+            self._log.debug(u'Not a valid Beatport release ID.')
             return None
         release = self.client.get_release(match.group(2))
-        album = self._get_album_info(release)
-        return album
+        if release:
+            return self._get_album_info(release)
+        return None
 
     def track_for_id(self, track_id):
         """Fetches a track by its Beatport ID and returns a TrackInfo object
-        or None if the track is not found.
+        or None if the track is not a valid Beatport ID or track is not found.
         """
         self._log.debug(u'Searching for track {0}', track_id)
         match = re.search(r'(^|beatport\.com/track/.+/)(\d+)$', track_id)
         if not match:
+            self._log.debug(u'Not a valid Beatport track ID.')
             return None
         bp_track = self.client.get_track(match.group(2))
-        track = self._get_track_info(bp_track)
-        return track
+        if bp_track is not None:
+            return self._get_track_info(bp_track)
+        return None
 
     def _get_releases(self, query):
         """Returns a list of AlbumInfo objects for a beatport search query.
diff --git a/docs/changelog.rst b/docs/changelog.rst
index aa87929c6..261b74505 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -107,6 +107,8 @@ Fixes:
 * ``none_rec_action`` does not import automatically when ``timid`` is enabled.
   Thanks to :user:`RollingStar`.
   :bug:`3242`
+* Fix a bug that caused a crash when tagging items with the beatport plugin.
+  :bug:`3374`
 
 For plugin developers:
 

beatport plugin failing 
Hi,

 Trying to test the fix made by @temrix on the beatport plugin but i get errors on any file

Running this command in verbose (`-vv`) mode:

```sh
$ beet -vv import /mnt/d/test/
```

Led to this problem:

```
user configuration: /root/.config/beets/config.yaml
data directory: /root/.config/beets
plugin paths:
Sending event: pluginload
library database: /mnt/d/Music/musiclibrary.db
library directory: /mnt/d/Music
Sending event: library_opened
Sending event: import_begin
Sending event: import_task_created
Sending event: import_task_start
Looking up: /mnt/d/test
Tagging Bawrut - 4x4 (Remixes)
No album ID found.
Search terms: Bawrut - 4x4 (Remixes)
Album might be VA: False
Searching for MusicBrainz releases with: {'release': u'4x4 (remixes)', 'tracks': u'1', 'artist': u'bawrut'}
Requesting MusicBrainz release f68de3a5-30e1-4849-bde5-7237833ee9f9
primary MB release type: single
Sending event: albuminfo_received
Candidate: Bawrut - Ciquita (f68de3a5-30e1-4849-bde5-7237833ee9f9)
Computing track assignment...
...done.
Success. Distance: 0.56
Requesting MusicBrainz release dda48d1f-cf31-47ba-9713-c4414ddef4c2
primary MB release type: ep
Sending event: albuminfo_received
Candidate: Wilmer X - 4x4 (dda48d1f-cf31-47ba-9713-c4414ddef4c2)
Computing track assignment...
...done.
Success. Distance: 0.75
Requesting MusicBrainz release b4c65504-6bd0-4ff8-97a7-9df3ee838b2c
primary MB release type: album
Sending event: albuminfo_received
Candidate: La Unión - 4x4 (b4c65504-6bd0-4ff8-97a7-9df3ee838b2c)
Computing track assignment...
...done.
Success. Distance: 0.80
Requesting MusicBrainz release 207c7744-b6a0-4f10-ab7c-a7b216106121
primary MB release type: album
Sending event: albuminfo_received
Candidate: McCoy Tyner Quartets - 4x4 (207c7744-b6a0-4f10-ab7c-a7b216106121)
Computing track assignment...
...done.
Success. Distance: 0.81
Requesting MusicBrainz release 8a204bbf-7a58-4421-aa19-512590dbfc1c
primary MB release type: ep
Sending event: albuminfo_received
Candidate: Works Progress Administration - 4X4 (8a204bbf-7a58-4421-aa19-512590dbfc1c)
Computing track assignment...
...done.
Success. Distance: 0.71
Traceback (most recent call last):
  File "/usr/local/bin/beet", line 11, in <module>
    load_entry_point('beets==1.5.0', 'console_scripts', 'beet')()
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/__init__.py", line 1267, in main
    _raw_main(args)
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/__init__.py", line 1254, in _raw_main
    subcommand.func(lib, suboptions, subargs)
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/commands.py", line 956, in import_func
    import_files(lib, paths, query)
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/commands.py", line 926, in import_files
    session.run()
  File "/usr/local/lib/python2.7/dist-packages/beets/importer.py", line 329, in run
    pl.run_parallel(QUEUE_SIZE)
  File "/usr/local/lib/python2.7/dist-packages/beets/util/pipeline.py", line 445, in run_parallel
    six.reraise(exc_info[0], exc_info[1], exc_info[2])
  File "/usr/local/lib/python2.7/dist-packages/beets/util/pipeline.py", line 312, in run
    out = self.coro.send(msg)
  File "/usr/local/lib/python2.7/dist-packages/beets/util/pipeline.py", line 194, in coro
    func(*(args + (task,)))
  File "/usr/local/lib/python2.7/dist-packages/beets/importer.py", line 1353, in lookup_candidates
    task.lookup_candidates()
  File "/usr/local/lib/python2.7/dist-packages/beets/importer.py", line 641, in lookup_candidates
    autotag.tag_album(self.items, search_ids=self.search_ids)
  File "/usr/local/lib/python2.7/dist-packages/beets/autotag/match.py", line 460, in tag_album
    va_likely):
  File "/usr/local/lib/python2.7/dist-packages/beets/plugins.py", line 576, in decorated
    for v in generator(*args, **kwargs):
  File "/usr/local/lib/python2.7/dist-packages/beets/autotag/hooks.py", line 637, in album_candidates
    for candidate in plugins.candidates(items, artist, album, va_likely):
  File "/usr/local/lib/python2.7/dist-packages/beets/plugins.py", line 386, in candidates
    for candidate in plugin.candidates(items, artist, album, va_likely):
  File "/usr/local/lib/python2.7/dist-packages/beetsplug/beatport.py", line 360, in candidates
    return self._get_releases(query)
  File "/usr/local/lib/python2.7/dist-packages/beetsplug/beatport.py", line 412, in _get_releases
    for x in self.client.search(query)]
  File "/usr/local/lib/python2.7/dist-packages/beetsplug/beatport.py", line 138, in search
    release = self.get_release(item['id'])
  File "/usr/local/lib/python2.7/dist-packages/beetsplug/beatport.py", line 154, in get_release
    release.tracks = self.get_release_tracks(beatport_id)
  File "/usr/local/lib/python2.7/dist-packages/beetsplug/beatport.py", line 166, in get_release_tracks
    return [BeatportTrack(t) for t in response]
  File "/usr/local/lib/python2.7/dist-packages/beetsplug/beatport.py", line 265, in __init__
    self.genre = six.text_type(data['subGenres'][0].get('name'))
IndexError: list index out of range
```

Here's a link to the music files that trigger the bug (if relevant):
https://www.beatport.com/track/more-cowbell-jimpster-remix/10656680
https://www.beatport.com/track/shakti-pan-feat-sven-original-mix/9130725
etc.
Basically any track i tried

### Setup

* OS: Ubuntu 18.04
* Python version: 2.7.15
* beets version: 1.5.0 (latest from git)

My configuration (output of `beet config`) is:

```yaml
paths:
    default: $genre/$year_$month/$artist_$title
    singleton: $genre/$year_$month/$artist_$title
library: /mnt/d/Music/musiclibrary.db

replace:
    '[\\/]': _
    ^\.: _
    '[\x00-\x1f]': _
    '[<>:"\?\*\|]': _
    \.$: _
    \s+$: ''
original_date: yes
path_sep_replace: _

plugins: inline beatport
directory: /mnt/d/Music

import:
    move: no
    copy: yes
    write: yes
beatport:
    source_weight: 1
    tokenfile: beatport_token.json
    apikey: REDACTED
    apisecret: REDACTED
pathfields: {}
album_fields: {}
item_fields: {}
```

Thank you.
diff --git a/test/test_beatport.py b/test/test_beatport.py
index a1591d58c..8e830df76 100644
--- a/test/test_beatport.py
+++ b/test/test_beatport.py
@@ -31,7 +31,7 @@ class BeatportTest(_common.TestCase, TestHelper):
     def _make_release_response(self):
         """Returns a dict that mimics a response from the beatport API.
 
-        The results were retrived from:
+        The results were retrieved from:
         https://oauth-api.beatport.com/catalog/3/releases?id=1742984
         The list of elements on the returned dict is incomplete, including just
         those required for the tests on this class.
@@ -72,7 +72,7 @@ class BeatportTest(_common.TestCase, TestHelper):
     def _make_tracks_response(self):
         """Return a list that mimics a response from the beatport API.
 
-        The results were retrived from:
+        The results were retrieved from:
         https://oauth-api.beatport.com/catalog/3/tracks?releaseId=1742984
         The list of elements on the returned list is incomplete, including just
         those required for the tests on this class.
@@ -425,7 +425,6 @@ class BeatportTest(_common.TestCase, TestHelper):
 
         # Set up 'test_album'.
         self.test_album = self.mk_test_album()
-        # print(self.test_album.keys())
 
         # Set up 'test_tracks'
         self.test_tracks = self.test_album.items()
@@ -559,6 +558,70 @@ class BeatportTest(_common.TestCase, TestHelper):
             self.assertEqual(track.genre, test_track.genre)
 
 
+class BeatportResponseEmptyTest(_common.TestCase, TestHelper):
+    def _make_tracks_response(self):
+        results = [{
+            "id": 7817567,
+            "name": "Mirage a Trois",
+            "genres": [{
+              "id": 9,
+              "name": "Breaks",
+              "slug": "breaks",
+              "type": "genre"
+            }],
+            "subGenres": [{
+              "id": 209,
+              "name": "Glitch Hop",
+              "slug": "glitch-hop",
+              "type": "subgenre"
+            }],
+        }]
+        return results
+
+    def setUp(self):
+        self.setup_beets()
+        self.load_plugins('beatport')
+        self.lib = library.Library(':memory:')
+
+        # Set up 'tracks'.
+        self.response_tracks = self._make_tracks_response()
+        self.tracks = [beatport.BeatportTrack(t) for t in self.response_tracks]
+
+        # Make alias to be congruent with class `BeatportTest`.
+        self.test_tracks = self.response_tracks
+
+    def tearDown(self):
+        self.unload_plugins()
+        self.teardown_beets()
+
+    def test_response_tracks_empty(self):
+        response_tracks = []
+        tracks = [beatport.BeatportTrack(t) for t in response_tracks]
+        self.assertEqual(tracks, [])
+
+    def test_sub_genre_empty_fallback(self):
+        """No 'sub_genre' is provided. Test if fallback to 'genre' works.
+        """
+        self.response_tracks[0]['subGenres'] = []
+        tracks = [beatport.BeatportTrack(t) for t in self.response_tracks]
+
+        self.test_tracks[0]['subGenres'] = []
+
+        self.assertEqual(tracks[0].genre,
+                         self.test_tracks[0]['genres'][0]['name'])
+
+    def test_genre_empty(self):
+        """No 'genre' is provided. Test if 'sub_genre' is applied.
+        """
+        self.response_tracks[0]['genres'] = []
+        tracks = [beatport.BeatportTrack(t) for t in self.response_tracks]
+
+        self.test_tracks[0]['genres'] = []
+
+        self.assertEqual(tracks[0].genre,
+                         self.test_tracks[0]['subGenres'][0]['name'])
+
+
 def suite():
     return unittest.TestLoader().loadTestsFromName(__name__)
 

pip install -e .[dev]
parse_log_pytest
pytest
nose nose-show-skipped nose-cov coverage beautifulsoup4 flask mock pylast rarfile responses pyxdg python-mpd2 discogs-client requests_oauthlib pytest
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
anyio==4.9.0
beautifulsoup4==4.13.3
-e git+https://github.com/beetbox/beets.git@db7ef0e60e9b794fe3dd05a7bada424d6b008cbc#egg=beets
blinker==1.9.0
certifi==2025.1.31
charset-normalizer==3.4.1
click==8.1.8
confuse==2.0.1
cov-core==1.15.0
coverage==7.8.0
discogs-client==2.3.0
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
filetype==1.2.0
Flask==3.1.0
h11==0.14.0
httpcore==1.0.7
httpx==0.28.1
idna==3.10
importlib_metadata==8.6.1
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
itsdangerous==2.2.0
jellyfish==1.2.0
Jinja2==3.1.6
MarkupSafe==3.0.2
mediafile==0.13.0
mock==5.2.0
munkres==1.1.4
musicbrainzngs==0.7.1
mutagen==1.47.0
nose==1.3.7
nose-cov==1.6
nose-show-skipped==0.1
oauthlib==3.2.2
packaging @ file:///croot/packaging_1734472117206/work
pluggy @ file:///croot/pluggy_1733169602837/work
pylast==5.5.0
pytest @ file:///croot/pytest_1738938843180/work
python-mpd2==3.1.1
pyxdg==0.28
PyYAML==6.0.2
rarfile==4.2
requests==2.32.3
requests-oauthlib==2.0.0
responses==0.25.7
six==1.17.0
sniffio==1.3.1
soupsieve==2.6
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
typing_extensions==4.13.0
Unidecode==1.3.8
urllib3==2.3.0
Werkzeug==3.1.3
zipp==3.21.0

name: beets
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - anyio==4.9.0
      - beautifulsoup4==4.13.3
      - blinker==1.9.0
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - click==8.1.8
      - confuse==2.0.1
      - cov-core==1.15.0
      - coverage==7.8.0
      - discogs-client==2.3.0
      - filetype==1.2.0
      - flask==3.1.0
      - h11==0.14.0
      - httpcore==1.0.7
      - httpx==0.28.1
      - idna==3.10
      - importlib-metadata==8.6.1
      - itsdangerous==2.2.0
      - jellyfish==1.2.0
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - mediafile==0.13.0
      - mock==5.2.0
      - munkres==1.1.4
      - musicbrainzngs==0.7.1
      - mutagen==1.47.0
      - nose==1.3.7
      - nose-cov==1.6
      - nose-show-skipped==0.1
      - oauthlib==3.2.2
      - pylast==5.5.0
      - python-mpd2==3.1.1
      - pyxdg==0.28
      - pyyaml==6.0.2
      - rarfile==4.2
      - requests==2.32.3
      - requests-oauthlib==2.0.0
      - responses==0.25.7
      - six==1.17.0
      - sniffio==1.3.1
      - soupsieve==2.6
      - typing-extensions==4.13.0
      - unidecode==1.3.8
      - urllib3==2.3.0
      - werkzeug==3.1.3
      - zipp==3.21.0
prefix: /opt/conda/envs/beets

test/test_beatport.py::BeatportResponseEmptyTest::test_sub_genre_empty_fallback
test/test_beatport.py::BeatportTest::test_album_name_applied test/test_beatport.py::BeatportTest::test_album_url_applied test/test_beatport.py::BeatportTest::test_bpm_applied test/test_beatport.py::BeatportTest::test_catalog_number_applied test/test_beatport.py::BeatportTest::test_category_applied test/test_beatport.py::BeatportTest::test_genre_applied test/test_beatport.py::BeatportTest::test_label_applied test/test_beatport.py::BeatportTest::test_length_applied test/test_beatport.py::BeatportTest::test_mix_name_applied test/test_beatport.py::BeatportTest::test_musical_key_applied test/test_beatport.py::BeatportTest::test_title_applied test/test_beatport.py::BeatportTest::test_track_url_applied test/test_beatport.py::BeatportResponseEmptyTest::test_genre_empty test/test_beatport.py::BeatportResponseEmptyTest::test_response_tracks_empty
docs/changelog.rst beetsplug/beatport.py
docs/changelog.rst beetsplug/beatport.py