beets icon indicating copy to clipboard operation
beets copied to clipboard

beet import -s fails with "at least one query term is required"

Open sgued opened this issue 3 months ago • 10 comments

I'm trying to import a bunch of songs to my library, using beet import -s .

Problem

Running this command in verbose (-vv) mode:

beet -vv import -s . 

Led to this problem:

user configuration: /home/soso/.config/beets/config.yaml
data directory: /home/soso/.config/beets
plugin paths: []
Loading plugins: musicbrainz
Sending event: pluginload
library database: /home/soso/.config/beets/library.db
library directory: /home/soso/Music
Sending event: library_opened
Sending event: import_begin
Sending event: import_task_created
Sending event: import_task_start
Looking up: /home/soso/Downloads/music/Agar Agar ~ Prettiest Virgin [Yp257b5APOg].opus
Item search terms:  -
musicbrainz: Searching for MusicBrainz recordings with: {}
Sending event: import_task_created
Traceback (most recent call last):
  File "/usr/bin/beet", line 8, in <module>
    sys.exit(main())
             ~~~~^^
  File "/usr/lib/python3.13/site-packages/beets/ui/__init__.py", line 1713, in main
    _raw_main(args)
    ~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/site-packages/beets/ui/__init__.py", line 1692, in _raw_main
    subcommand.func(lib, suboptions, subargs)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/beets/ui/commands.py", line 1378, in import_func
    import_files(lib, byte_paths, query)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/beets/ui/commands.py", line 1322, in import_files
    session.run()
    ~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/beets/importer/session.py", line 234, in run
    pl.run_parallel(QUEUE_SIZE)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/beets/util/pipeline.py", line 468, in run_parallel
    raise exc_info[1].with_traceback(exc_info[2])
  File "/usr/lib/python3.13/site-packages/beets/util/pipeline.py", line 333, in run
    out = self.coro.send(msg)
  File "/usr/lib/python3.13/site-packages/beets/util/pipeline.py", line 216, in coro
    func(*(args + (task,)))
    ~~~~^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/beets/importer/stages.py", line 144, in lookup_candidates
    task.lookup_candidates(session.config["search_ids"].as_str_seq())
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/beets/importer/tasks.py", line 686, in lookup_candidates
    self.candidates, self.rec = autotag.tag_item(
                                ~~~~~~~~~~~~~~~~^
        self.item, search_ids=search_ids
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/usr/lib/python3.13/site-packages/beets/autotag/match.py", line 373, in tag_item
    for track_info in metadata_plugins.item_candidates(
                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        item, search_artist, search_title
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ):
    ^
  File "/usr/lib/python3.13/site-packages/beets/plugins.py", line 473, in wrapper
    for v in func(*args, **kwargs):
             ~~~~^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/beets/metadata_plugins.py", line 69, in item_candidates
    yield from plugin.item_candidates(*args, **kwargs)
  File "/usr/lib/python3.13/site-packages/beetsplug/musicbrainz.py", line 837, in item_candidates
    None, map(self.track_info, self._search_api("recording", criteria))
                               ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/beetsplug/musicbrainz.py", line 812, in _search_api
    res = method(limit=self.config["search_limit"].get(), **filters)
  File "/usr/lib/python3.13/site-packages/musicbrainzngs/musicbrainz.py", line 971, in search_recordings
    return _do_mb_search('recording', query, fields, limit, offset, strict)
  File "/usr/lib/python3.13/site-packages/musicbrainzngs/musicbrainz.py", line 773, in _do_mb_search
    raise ValueError('at least one query term is required')
ValueError: at least one query term is required

There needs to be at least on music file in the directory where this is called. An empty opus file generated by ffmpeg is enough: ffmpeg -f lavfi -i anullsrc -ac 2 -ar 48000 -t 30 -c:a libopus file.opus

Setup

  • OS:  Arch Linux
  • Python version: 3.13.7
  • beets version: beets version 2.4.0
  • Turning off plugins made problem go away (yes/no): yes (the only plugin I use is musicbrainz)

Config:

disabled_plugins: []
musicbrainz:
    search_limit: 5
    source_weight: 0.5
    host: musicbrainz.org
    https: no
    ratelimit: 1
    ratelimit_interval: 1
    genres: no
    external_ids:
        discogs: no
        bandcamp: no
        spotify: no
        deezer: no
        tidal: no
    extra_tags: []

sgued avatar Oct 01 '25 19:10 sgued

Hi, thanks for the report!

Can you give us some guidance on how to reproduce this? For me singleton import -s works without an issue.

semohr avatar Oct 02 '25 10:10 semohr

I'm guessing there are no tags in the file.

arsaboo avatar Oct 02 '25 10:10 arsaboo

I'm guessing there are no tags in the file.

Thought the same. Still beets shouldn't crash if no metadata is available imo 😨

edit: see Item search terms: - in provided logs

semohr avatar Oct 02 '25 10:10 semohr

@arsaboo How do you think we should handle this? I see two main options:

  • Enforce that we do not allow empty metadata in the autotag layer (skip lookup entirely if artist and title not given)
  • Let every plugin decide on their own how to handle cases where artist = title = ""

I tend toward option one, but I’m not sure if it might be too restrictive. For example, the chroma plugin doesn’t rely on artist or title.

Another possibility is to type search_artist/search_title as str | None instead of str. This adds a bit of complexity but makes it explicit for metadata plugins that these fields can be empty.

semohr avatar Oct 02 '25 11:10 semohr

For my use case (generally music downloaded from YT), I'd rather have beet use the file name as the song title when no tags are present.

sgued avatar Oct 02 '25 11:10 sgued

For my use case (generally music downloaded from YT), I'd rather have beet use the file name as the song title when no tags are present.

I don't see why this couldn't be added too 👍. It is more of additional thing tho as this does not solve the underlying issue. Filename can also be empty (e.g. " .mp3" is valid afaik).

semohr avatar Oct 02 '25 11:10 semohr

@sgued you should use the FromFilename plugin for that.

@semohr Agreed. If no metadata is provided, we can simply skip (possibly with a log).

arsaboo avatar Oct 02 '25 11:10 arsaboo

Looking at this, I thought it can't possibly be the very first time this issue is popping up, and it seems I found what I wanted to see: https://github.com/beetbox/beets/issues/1029

@sampsyo's original fix confirms your suggestion @arsaboo:

@semohr Agreed. If no metadata is provided, we can simply skip (possibly with a log).

snejus avatar Oct 02 '25 22:10 snejus

Oh my god this drove me insane for 2 weeke

Is this a new bug??? I never had this crash before and now i have it once evry 10 files

Any solution?

king8084 avatar Oct 20 '25 09:10 king8084

My solution is to manually tag just the part of the titles manually before doing the import. Anyway for a while I've needed to search manually for each file, so it's not much more work. For that I use Tagger, which is OK at this.

sgued avatar Nov 16 '25 16:11 sgued