glob.glob() Over-Matches Filenames Containing * or ? (tested)
A filename can legally contain a literal * or ? character. We measured what happens when that exact filename is handed straight to glob.glob(), and it silently grabs extra files that were never meant to match.
1. A literal '*' in a filename is parsed as a wildcard, not matched as itself
import glob
# directory contains: 'data*.csv', 'data1.csv', 'data2.csv'
target = "data*.csv" # the real, literal filename on disk
print(sorted(glob.glob(target)))
['data*.csv', 'data1.csv', 'data2.csv']
Measured: passing the file's own name straight to glob.glob() returned three files, not one. The * in "data*.csv" was compiled as "zero or more of any character", so it matched its own literal file plus two completely unrelated ones -- with no error or warning that the string was treated as a pattern rather than a name.
2. pathlib.Path.glob() has the identical behaviour
from pathlib import Path
target = "data*.csv"
print(sorted(str(p) for p in Path(".").glob(target)))
['data*.csv', 'data1.csv', 'data2.csv']
Measured: Path.glob() builds on the same pattern-compilation logic as the glob module, so it over-matches the exact same way. Code that loops filenames from os.listdir() or a database and re-globs each one to "find" it is silently vulnerable to this if any filename contains * or ? -- both are legal in POSIX filenames.
3. Fix: wrap any filename from outside your control in glob.escape()
import glob
target = "data*.csv"
pattern = glob.escape(target)
print("escaped pattern:", pattern)
print(sorted(glob.glob(pattern)))
escaped pattern: data[*].csv
['data*.csv']
Measured: glob.escape() rewrites the literal * into the bracket form [*], which glob's own parser treats as "match the single literal character *" rather than a wildcard. With escaping, the call returns exactly the one file it was given and nothing else. This is the same fix as for filenames containing literal brackets -- escape first whenever the name itself, not a pattern you authored, is the input.
Frequently asked questions
Does glob.glob() treat a literal '*' in a filename as a wildcard?
Yes -- we measured it compiling '*' as a wildcard even when the exact string passed in was the file's own name, causing two unrelated files to be returned alongside it.
Does glob.glob() raise an error when a filename contains * or ?
No -- we saw no exception or warning. It silently returned extra matches with no indication the input string had been treated as a pattern.
Does pathlib.Path.glob() have the same over-matching problem?
Yes -- we confirmed Path.glob() returned the identical three files for the identical literal filename, since it shares the same pattern-compilation logic as the glob module.
How do I glob for a file by its exact name safely?
Wrap the filename in glob.escape() before passing it to glob.glob() or Path.glob() -- we measured this correctly restricting the match to only the one literal file.
Is a literal * or ? in a filename actually possible?
Yes -- both are legal characters in POSIX filenames (just not on Windows), and can show up from exports, renamed downloads, or user-supplied names, making this a realistic real-world trap, not just a contrived one.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in glob module: created a file literally named 'data*.csv' alongside two unrelated files 'data1.csv' and 'data2.csv', then passed the literal filename straight to glob.glob() with and without glob.escape(). PlainHeaders is our extension; Python's glob module is built in.