Tags are being written to imported files even though "import.write: no"

I’m setting up Beets and importing a few albums to test my configuration. No matter what I can think to try, matched tags are always written to the imported files.

I’m using the linuxserver.io docker container.

I have “write: no” in my configuration, which seems to explicitly state that it will not write tags. This does stop fetched artwork from being embedded, for example, but tags like ARTIST and MUSICBRAINZ_ALBUMID are always written.

I’ve tried disabling chroma and switching from move to copy. Even disabling both move and copy results in the source files being modified in place.
I’ve also tried running import with -W to no change in behavior.

Am I misunderstanding the expected behavior? Do I have something misconfigured?

Thanks for any help.

Below is the output of beets config.

    bing_lang_from: []
    auto: no
    fallback: ''
    sources: genius
    bing_client_secret: REDACTED
    google_API_key: REDACTED
    google_engine_ID: REDACTED
    genius_api_key: REDACTED
    force: no
    local: no

- fetchart
- embedart
- convert
- scrub
- replaygain
- lyrics
- lastgenre
- the
- inline
- chroma
- web
- permissions
directory: /music
library: /config/musiclibrary.blb
art_filename: _cover
threaded: yes
original_date: yes
per_disc_numbering: yes
    auto: yes
    auto: no
    maxwidth: 0
    compare_threshold: 0
    ifempty: no
    remove_art_file: no
    quality: 0
    auto: no
    dest: /converted
    format: aac
            command: ffmpeg -i $source -c:a aac -vbr 4 $dest
            extension: m4a
            command: /config/gapless-mp3.sh $source $dest
            extension: mp3
            command: ffmpeg -i $source -y -vn -acodec alac $dest
            extension: m4a
        flac: ffmpeg -i $source -y -vn -acodec flac $dest
        opus: ffmpeg -i $source -y -vn -acodec libopus -ab 96k $dest
        ogg: ffmpeg -i $source -y -vn -acodec libvorbis -aq 3 $dest
        wma: ffmpeg -i $source -y -vn -acodec wmav2 -vn $dest
    pretend: no
    link: no
    hardlink: no
    threads: 8
    id3v23: inherit
    max_bitrate: 500
    quiet: no
    embed: yes

    paths: {}
    no_convert: ''
    never_convert_lossy_files: no
    copy_album_art: no
    album_art_maxwidth: 0
    delete_originals: no
    disc_and_track: u'%02i.%02i' % (disc, track) if disctotal > 1 else u'%02i' % (track)
    a: no
    the: yes
    format: '{0}, {1}'
    strip: no
    patterns: []

    default: '%the{$albumartist}/$original_year - $album%aunique{}/$disc_and_track $title'
    singleton: '%the{$albumartist}/_singles/$original_year - $title'
    comp: _Compilations/$original_year - $album%aunique{}/$disc_and_track $title
    albumtype_soundtrack: _Soundtracks/$original_year - $album%aunique{}/$disc_and_track $title
    file: 664
    dir: 775

    write: no
    copy: no
    move: yes
    resume: ask
    incremental: no
    quiet_fallback: skip
    timid: no
    log: /config/beet.log
    auto: yes
    source: album
    whitelist: yes
    min_weight: 10
    count: 1
    canonical: no
    force: yes
    separator: ', '
    prefer_specific: no
    title_case: yes
    auto: yes
    store_source: yes
    minwidth: 600
    - filesystem
    - coverart
    - itunes
    - albumart
    - amazon
    maxwidth: 0
    quality: 0
    max_filesize: 0
    enforce_ratio: no
    cautious: no
    - cover
    - front
    - art
    - album
    - folder
    google_key: REDACTED
    google_engine: 001442825323518660753:hrh5ch1gjzm
    fanarttv_key: REDACTED
    lastfm_key: REDACTED
    high_resolution: no
    deinterlace: no
    auto: yes
    backend: ffmpeg
    overwrite: no
    threads: 8
    parallel_on_import: no
    per_disc: no
    peak: 'true'
    targetlevel: 89
    r128: [Opus]
    r128_targetlevel: 84
    auto: yes

    ^\.: _
    '[\x00-\x1f]': _
    '[<>:"\?\*\|]': _
    '[\xE8-\xEB]': e
    '[\xEC-\xEF]': i
    '[\xE2-\xE6]': a
    '[\xF2-\xF6]': o
    '[\xF8]': o
    \.$: _
    \s+$: ''
    port: 8337
    cors: ''
    cors_supports_credentials: no
    reverse_proxy: no
    include_paths: no
    readonly: yes
pathfields: {}
album_fields: {}

Nothing looks immediately amiss. But this is a very large configuration—can you try disabling all plugins, for example, to see if the behavior persists? If so, some plugin is probably to blame, and you could find out which by selectively enabling them an testing things out.

The verbose output from an import may also reveal something.

Good thoughts on disabling plugins. The verbose output I’ve looked at wasn’t helpful (at least to me). I could see writes being called out, but nothing indicating writer was being enabled or anything.

I’ll try bisecting the plugins to see if one is interfering.

It’s the scrub plugin.
The _scrub_item(item, restore=True) method uses the restore argument to write tags back to the file after scrubbing. There are two entry points for the _scrub_item method: scrub_func(lib, opts, args) and import_task_files(self, session, task). The first is executed when called with beet scrub and looks at import.write and -W for passing to restore. The second method is called during an import and I didn’t see any way for the configuration and arguments to be accessed.

I’d think there should be a configuration item available in the scrub section that would allow scrubbing, without rewriting; something like: scrub_only, restore, rewrite, etc.
As is, the scrub documentation does say that import.write needs to be on.

When importing new files (with import.write turned on) or modifying files’ tags with the beet modify command, beets will first strip all types of tags entirely and then write the database-tracked metadata to the file.

I should probably open a ticket to resolve this.

In my case, I think I’m fine with the current behavior as I’m eventually going to want those tags to be in place.

Thanks for your help.

1 Like

Just to close the reference loop, here’s the link to the ticket I opened: The scrub plugin rewrites tags even if import.write is disabled · Issue #4326 · beetbox/beets · GitHub

Do you think there was enough debug log text to debug it? The logging here looks above board but idk what it looks like in a real import.

This is also making me wonder if there’s some way to design beets to make logging of “important” / “system” tasks handled by beets itself, not the responsibility of the plugin author.

I think there’s enough debug logging. I might be tempted to promote the logging regarding scrubbing and restoring from debug to info. On the other hand, updating the documentation or fixing the behavior to match the existing documentation should be enough to resolve the expected and actual behavior.