tarfile.open() Write Mode Ignores the .tar.gz Extension (tested)

tarfile.open() can auto-detect compression when reading a file. We measured whether it does the same when writing one named .tar.gz — it doesn't. The mode string, not the filename, decides.

1. Writing with mode="w" to a ".tar.gz" filename

import tarfile

with tarfile.open("test.tar.gz", "w") as tf:   # note: "w", not "w:gz"
    tf.add("hostname")
with open("test.tar.gz", "rb") as f:
    print(f.read(4))
b'./\x00\x00'

Measured: the first bytes are plain tar header bytes, not gzip's magic number (\x1f\x8b). tarfile.open(name, "w") writes an ordinary, uncompressed tar archive — it never looked at the .gz in the filename to decide whether to compress.

2. Python itself can still read it back — which hides the bug

with tarfile.open("test.tar.gz", "r") as tf:   # mode "r": auto-detect
    print(tf.getnames())
['hostname']

Measured: opening the same file with plain "r" works fine — tarfile's read-mode auto-detection inspects the actual bytes, not the extension, so it happily reads the uncompressed data back. If your only test is "write it, then read it back with tarfile," this bug is invisible.

3. Anything else expecting real gzip breaks

import gzip
with gzip.open("test.tar.gz", "rb") as f:
    f.read(10)
gzip.BadGzipFile: Not a gzipped file (b'./')
$ tar -tzf test.tar.gz
gzip: stdin: not in gzip format
tar: Child returned status 1

Measured: gzip.open() raises BadGzipFile, and the system tar -tzf command (the standard way to list a .tar.gz) refuses outright. Anyone downloading this file and using a normal gzip-aware tool — not just Python's own auto-detecting reader — hits a hard failure, with a file that looks completely normal (right name, right size, no error at creation time).

4. Fix: name the compression in the mode string

with tarfile.open("test2.tar.gz", "w:gz") as tf:
    tf.add("hostname")

with open("test2.tar.gz", "rb") as f:
    print(f.read(2))
b'\x1f\x8b'

Measured: "w:gz" produces real gzip magic bytes, and both gzip.open() and tar -tzf read it correctly. The rule confirmed here: for reading, plain "r" auto-detects gzip/bz2/xz/plain; for writing, you must spell out "w:gz", "w:bz2", or "w:xz" yourself — shutil.make_archive() sidesteps this entirely by taking a format name ("gztar") instead of a mode string, which is the safer API if you don't need tarfile's lower-level control.

Frequently asked questions

Does tarfile.open() pick compression based on the filename when writing?

No -- we measured tarfile.open('x.tar.gz', 'w') writing a plain, uncompressed tar archive; the mode string alone decides, not the extension.

Why did my .tar.gz file work when I tested it in Python but fail elsewhere?

Because tarfile's read mode 'r' auto-detects compression from the actual bytes, so Python can read an uncompressed file even with a .gz name. We confirmed gzip.open() and the system tar -tzf command both reject the same file.

How do I write a real gzip-compressed tar with the tarfile module?

Use mode 'w:gz' explicitly -- we confirmed this produces correct gzip magic bytes that gzip.open() and tar -tzf both read without error.

Is shutil.make_archive() safer for this?

Yes -- it takes a format name like 'gztar' instead of a mode string, so there's no mode-vs-extension mismatch to get wrong. We didn't need to test this failure mode with make_archive() since the API doesn't expose the mistake.

Does this affect reading compressed archives too?

No -- we confirmed reading with plain 'r' correctly auto-detects gzip, bz2, xz, or uncompressed tar from the file's actual contents. The mismatch only happens on the write side, where the mode string must be explicit.

Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in tarfile and gzip modules: wrote an archive with tarfile.open('test.tar.gz', 'w') (no compression mode in the string), inspected the resulting file's magic bytes, then tried to read it back with tarfile's own auto-detecting 'r' mode, gzip.open(), and the system tar command. PlainHeaders is our extension; Python's tarfile and gzip modules are built in.