Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OGG Vorbis file save fails: mutagen.ogg.error: unable to read full header; got b'\x00\x00' #591

Open
glanch opened this issue Jan 15, 2023 · 4 comments

Comments

@glanch
Copy link

glanch commented Jan 15, 2023

Good day,
I am trying to save meta data to an Ogg Vorbis file that currently has no . I only have problems with this file. Unfortunately, I don't know where it is from.
My code to write a tag to this file:

mutagen_file = mutagen.oggvorbis.OggVorbis("ogg_file")

mutagen_file["title"] = u"foo"
mutagen_file.save()

It throws the following error (incl. stack trace)

(stray-tagger-py3.10) ➜  stray-tagger git:(main) ✗  cd /home/christopher/Projects/stray-tagger
 ; /usr/bin/env /home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/bin/python /hom
e/christopher/.vscode-oss/extensions/ms-python.python-2022.20.2-universal/pythonFiles/lib/python/debugpy/adapter
/../../debugpy/launcher 49013 -- -m stray_tagger 
Traceback (most recent call last):
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/ogg.py", line 88, in __init__
    crc, segments) = struct.unpack("<4sBBqIIiB", header)
struct.error: unpack requires a buffer of 27 bytes

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/ogg.py", line 587, in save
    self.tags._inject(filething.fileobj, padding)
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/oggvorbis.py", line 147, in _inject
    OggPage.replace(fileobj, old_pages, new_pages)
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/ogg.py", line 436, in replace
    cls.renumber(fileobj, serial, sequence)
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/ogg.py", line 228, in renumber
    page = OggPage(fileobj)
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/ogg.py", line 90, in __init__
    raise error("unable to read full header; got %r" % header)
mutagen.ogg.error: unable to read full header; got b'\x00\x00'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/christopher/.vscode-oss/extensions/ms-python.python-2022.20.2-universal/pythonFiles/lib/python/debugpy/adapter/../../debugpy/launcher/../../debugpy/__main__.py", line 39, in <module>
    cli.main()
  File "/home/christopher/.vscode-oss/extensions/ms-python.python-2022.20.2-universal/pythonFiles/lib/python/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 430, in main
    run()
  File "/home/christopher/.vscode-oss/extensions/ms-python.python-2022.20.2-universal/pythonFiles/lib/python/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 317, in run_module
    run_module_as_main(options.target, alter_argv=True)
  File "/home/christopher/.vscode-oss/extensions/ms-python.python-2022.20.2-universal/pythonFiles/lib/python/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 229, in _run_module_as_main
    mod_name, mod_spec, code = _get_module_details(mod_name, _Error)
  File "/home/christopher/.vscode-oss/extensions/ms-python.python-2022.20.2-universal/pythonFiles/lib/python/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 186, in _get_module_details
    return _get_module_details(pkg_main_name, error)
  File "/home/christopher/.vscode-oss/extensions/ms-python.python-2022.20.2-universal/pythonFiles/lib/python/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 150, in _get_module_details
    __import__(pkg_name)
  File "/home/christopher/Projects/stray-tagger/stray_tagger/__init__.py", line 100, in <module>
    mutagen_file.save()
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/_util.py", line 160, in wrapper
    return func(self, h, *args, **kwargs)
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/ogg.py", line 589, in save
    reraise(self._Error, e, sys.exc_info()[2])
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/_util.py", line 47, in reraise
    raise tp(value).with_traceback(tb)
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/ogg.py", line 587, in save
    self.tags._inject(filething.fileobj, padding)
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/oggvorbis.py", line 147, in _inject
    OggPage.replace(fileobj, old_pages, new_pages)
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/ogg.py", line 436, in replace
    cls.renumber(fileobj, serial, sequence)
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/ogg.py", line 228, in renumber
    page = OggPage(fileobj)
  File "/home/christopher/.cache/pypoetry/virtualenvs/stray-tagger-O9q9BGp1-py3.10/lib/python3.10/site-packages/mutagen/ogg.py", line 90, in __init__
    raise error("unable to read full header; got %r" % header)
mutagen.oggvorbis.OggVorbisHeaderError: unable to read full header; got b'\x00\x00'

Before and after running the code above, I ran several ´oggz` commands to help with debugging:
Before running:

$ oggz comment -l ogg_file       
Vorbis: serialno 0000000000
        Vendor: (null)
$ oggz validate ogg_file
$ oggz info ogg_file
Content-Duration: 00:03:46.771

Vorbis: serialno 0000000000
        31122 packets in 2274 pages, 13.7 packets/page, 1.129% Ogg overhead
        Audio-Samplerate: 44100 Hz
        Audio-Channels: 2
$ oggz codecs ogg_file
vorbis
$ 

After running:

$ oggz comment -l ogg_file       
Vorbis: serialno 0000000000
        Vendor: (null)
        title: foo
$ oggz validate ogg_file
$ oggz info ogg_file
Content-Duration: 00:03:24.886

Vorbis: serialno 0000000000
        25722 packets in 2034 pages, 12.6 packets/page, 1.114% Ogg overhead
        Audio-Samplerate: 44100 Hz
        Audio-Channels: 2
$ oggz codecs ogg_file
$ 

I tried to understand the code, but I was not able to find the mistake or bad section in my file, nor what generally happens. Maybe somebody knows what is wrong with my file.

I unfortunately cannot provide the (corrupt?) file due to copyright. Also, I don't have any other files than that. But maybe you can guide me through debugging this issue.

@glanch glanch changed the title OGG Vorbis file save fails OGG Vorbis file save fails: mutagen.ogg.error: unable to read full header; got b'\x00\x00' Jan 15, 2023
@phw
Copy link
Collaborator

phw commented Feb 14, 2023

Without a file to look into it's not really possible to say much about this. mutagen fails reading an ogg page header inside the file, so it looks like there is at least some corrupted data structure inside the file.

@niclimcy
Copy link

niclimcy commented Oct 5, 2023

Without a file to look into it's not really possible to say much about this. mutagen fails reading an ogg page header inside the file, so it looks like there is at least some corrupted data structure inside the file.

I have the same issue and have a file I can share. How can I share you the file privately?

@JanGross
Copy link

JanGross commented Jan 8, 2024

Ran into the same issue.
As a quick workaround you can disable metadata padding during save:

mutagen_file.save(padding=lambda info: 0)

Ref.: https://mutagen.readthedocs.io/en/latest/user/padding.html

Attached below is a test file and a minimal example to reproduce the issue
Sinewave_Sweep.zip

import mutagen

file_path = "Sinewave_Sweep.ogg"
mutagen_handle = mutagen.File(file_path)

mutagen_handle["artist"] = u'AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB'
mutagen_handle["title"] = u'CCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDD'
mutagen_handle["album"] = u'EEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFF'
mutagen_handle["comment"] = u'GGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHH'  

mutagen_handle.save()

From my example
Header at offset 2899534
b'OggS\x00\x04\xac\xaak\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x02\x00\x00\x87\xb8\x86\xa7\x10'
oggs b'OggS', version 0, type flags 4, position 7056044, serial 0, sequence 678, crc -1484343161, segments 16
Header at offset 2902121
b'\x00\x00' -> throws in ogg.py line 91 trying to struct.unpack("<4sBBqIIiB", ..) these bytes.

It always throws at the last Ogg page, trying to interpret the last couple null bytes as a header.
The file still gets saved and once ran, the same ogg file will no longer cause the issue.

However, the offsets also wildly change. On the file that errored previously the last two segments are now
Header at offset 27
b'OggS\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#SN\xcb\x01'
oggs b'OggS', version 0, type flags 2, position 0, serial 0, sequence 0, crc -884059357, segments 1
Header at offset 85
b'OggS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\xe6\xe6(\x8e\x11'
oggs b'OggS', version 0, type flags 0, position 0, serial 0, sequence 1, crc -1909922074, segments 17

The same error will return once if you massively increase the size of the metadata (say * 100 for each tag).
(also if the metadata is being reduced a lot)
Maybe there's something in the file messing up the padding calculation when resizing the metadata section.

Couldn't tell what about my file is corrupt though. I hope someone more familiar with the format can spot the problem :)

@big-lip-bob
Copy link

The library is not handling trailing null bytes in the file, not even sure in which cases EOFError is relevant.

The fix applies when all the trailing bytes are null bytes so the check would essentially look like this instead of the raise EOFError, as it seems to work in my case.

    if all(not byte in header):
        if not all(not byte in fileobj.read()):
            raise error("non-null bytes trailing at %d" % self.offset)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants