Skip to content
Quasar Tools Logo

Fix FilenameSanitizer InvalidCharError in Python

How to fix the FilenameSanitizer InvalidCharError in Python — what causes it, which characters are illegal on each OS, and how to sanitize filenames correctly in your code.

DH
Tutorials & How-Tos11 min read2,550 words

The `InvalidCharError` from Python's filename sanitizer libraries is a precise error — it fires when a filename string contains a character that the target operating system forbids. But the cause is almost always the same: a filename arrived from user input, a file upload, or an external API without being validated first. This guide explains exactly which characters trigger the error on each OS, how to fix it, and how to build sanitization into your code so it never reaches production.

11Illegal chars on Windows< > : " / \ | ? * and more
2Illegal chars on LinuxOnly null byte and forward slash
255Max filename bytesCross-platform safe limit

What is FilenameSanitizer?

`FilenameSanitizer` refers to Python libraries — most commonly `python-filenamesanitizer` and similar packages — that validate and clean filename strings before they are used in filesystem operations. These libraries check the proposed filename against the rules of the target operating system and either return a sanitized version or raise an exception when a character cannot be safely replaced.

Why filename sanitization is necessary

Filenames that come from external sources — user uploads, API responses, scraped data, database records — frequently contain characters that are perfectly valid in the source context but illegal on the destination filesystem. A filename like `report: Q1/2026.pdf` is a reasonable human label, but it contains `:` and `/` — both illegal on Windows. Without sanitization, the `open()` call raises an `OSError` or the file is silently truncated at the illegal character.

What InvalidCharError means

`InvalidCharError` is the specific exception raised when a filename contains a character that the library cannot automatically replace or strip — or when the library is configured to raise rather than auto-fix. The exception message includes the original filename and the offending character, which gives you everything you need to fix it. If you are seeing this error without a clear traceback, paste the full stack trace into the Python Traceback Explainer for a plain-English breakdown of the root cause.

Note

Not all filename errors in Python come from a sanitizer library. An identical `ValueError` or `OSError` can be raised directly by `open()`, `os.rename()`, `pathlib.Path()`, or `shutil` when an unsanitized filename reaches a filesystem call. The fix is the same regardless of which call raised the error — the filename must be cleaned before it reaches any filesystem operation.

What triggers InvalidCharError?

The error fires when the filename string contains one or more characters that the sanitizer's rule set marks as illegal. The most common triggers fall into four categories, each with a different fix path.

  • Windows path separator characters — `:` (colon), `\` (backslash), `/` (forward slash); these appear frequently in timestamps and URL paths used as filenames
  • Shell-reserved characters — `|`, `&lt;`, `&gt;`, `?`, `*`, `"` — common in filenames generated from search queries, titles, or document names
  • Null bytes and control characters — Unicode codepoints U+0000 to U+001F; sometimes injected by malicious input or encoding corruption
  • Windows reserved device names — CON, PRN, AUX, NUL, COM1–COM9, LPT1–LPT9 — illegal as filenames regardless of extension on Windows

The timestamp problem

The single most common source of `InvalidCharError` in real applications is a filename constructed from a timestamp. An ISO 8601 datetime like `2026-06-11T14:30:00` contains a colon — illegal on Windows. Any code that generates filenames like `backup_2026-06-11T14:30:00.zip` will fail on Windows but silently succeed on Linux, creating a subtle cross-platform bug. Replace colons in timestamps with hyphens or dots: `2026-06-11T14-30-00`.

The user input problem

When users name files in a web interface or upload files from their devices, the names arrive without any guarantee of validity. A PDF named `Invoice: Client/Project Q4.pdf` is a completely natural human-written name that contains three characters illegal on Windows. Always treat any filename that did not originate from your own code as untrusted input that requires sanitization before use.

Warning

Never assume that a filename is safe just because it survived on the source system. Linux allows filenames with `<`, `>`, `*`, and `|` — files with these names can be uploaded from a Linux machine and then cause `InvalidCharError` when your Windows-targeting code tries to write them. Always sanitize regardless of where the filename came from.

Illegal characters by OS

The three major operating systems have very different rules about which characters are allowed in filenames. Understanding the differences is essential for writing portable file-handling code.

CharacterWindowsmacOSLinux
/ (forward slash)✗ Illegal✗ Illegal✗ Illegal (path sep)
\ (backslash)✗ Illegal✓ Allowed✓ Allowed
: (colon)✗ Illegal✗ Legacy issue✓ Allowed
* ? " < > | (set)✗ Illegal✓ Allowed✓ Allowed
Null byte (\0)✗ Illegal✗ Illegal✗ Illegal
Control chars (0–31)✗ Illegal✗ Illegal✗ Illegal
Leading dot (.)✓ AllowedHidden fileHidden file
Trailing dot or space✗ Illegal✓ Allowed✓ Allowed
Reserved names (CON etc.)✗ Illegal✓ Allowed✓ Allowed

For cross-platform code that must work on all three systems, the safe rule is to treat Windows rules as the minimum — any character illegal on Windows should be sanitized regardless of the actual runtime OS. This gives you portable filenames that work everywhere. The Filename Sanitizer for Cross-Platform Uploads validates against all three OS rule sets simultaneously so you can check any filename in a single pass.

How to fix the error

Fixing an `InvalidCharError` always involves the same workflow: find the source of the filename, apply sanitization before the filesystem call, and verify the result. Work through these steps in order.

1

Read the full traceback to identify the offending character

The `InvalidCharError` message includes both the original filename string and the specific character that was rejected. Copy the full traceback and note the character. If the character is a control character or null byte, it may not be visible in the error output — use `repr()` on the filename string in your code to see the escaped representation and identify the hidden characters.

2

Locate where the filename originates in your code

Trace the filename back to its source using the call stack in the traceback. Common sources: the `filename` field from a multipart upload, a string constructed from user-provided metadata, an API response field, a database column, or an external file listing. The fix location is always at the source — not at the point where the error is raised.

3

Apply sanitization at the input boundary

Add a sanitization pass immediately after the filename enters your system — at the upload handler, the API response parser, or wherever external data first becomes a filename. Use `re.sub(r'[<>:"/\\|?*\x00-\x1F]', '-', name)` as a baseline replacement, then strip trailing dots and spaces, check against reserved Windows names, and truncate to 255 bytes. Use the Python Syntax Validator to check your sanitizer function for any syntax errors before deploying.

4

Validate the sanitized filename before the filesystem call

After sanitization, validate the result with the Filename Sanitizer for Cross-Platform Uploads to confirm no illegal characters remain, the name is not a reserved Windows device name, and the length is within the 255-byte limit. This catches edge cases that simple regex substitution misses — like a filename that is entirely composed of spaces after stripping, which becomes empty after trimming.

Filename Sanitizer for Cross-Platform Uploads

Paste any filename and validate it against Windows, macOS, and Linux rules simultaneously — identifies illegal characters, reserved names, length issues, and provides the clean safe version.

Open tool

Sanitizing filenames manually in Python

If you prefer not to depend on a third-party library, you can implement a robust filename sanitizer in pure Python. The approach covers all Windows and cross-platform restrictions without any external dependencies.

The core sanitization logic

A complete Python filename sanitizer needs five operations applied in sequence: normalize Unicode to composed form (NFC) so characters like accented letters are stored as single code points; replace all Windows-illegal characters and ASCII control characters with a safe substitute; strip leading and trailing dots, spaces, and hyphens which are problematic on Windows; check against the list of Windows reserved device names and append a suffix if matched; and finally truncate to 255 bytes when encoded as UTF-8.

Handling Unicode filenames

Modern applications routinely handle filenames containing non-ASCII characters — Arabic, Chinese, Japanese, accented Latin characters. These are all legal on modern filesystems (NTFS, APFS, ext4) but can cause issues when encoding conversions happen. A filename that is valid UTF-8 may become corrupt if the filesystem or OS is configured for a legacy encoding like Latin-1 or Windows-1252. If you encounter filenames with garbled characters, run them through the Unicode and Encoding Repair Tool to identify and fix the encoding problem before sanitization.


When to raise vs. when to auto-fix

You have two choices when an illegal character is found: raise an exception (the `python-filenamesanitizer` library's default) or auto-replace with a safe character. For upload handlers, auto-replacement is usually the right choice — silently cleaning `invoice: Q1.pdf` to `invoice- Q1.pdf` is better than failing the upload. For internal code that generates its own filenames, raising is better — an `InvalidCharError` in your own code is a bug to fix, not an edge case to handle silently.

Tip

When auto-replacing characters, prefer a hyphen (`-`) over an underscore as the replacement character. Hyphens are more readable than underscores in multi-word filenames and are universally allowed on all operating systems. Avoid replacing with a space — while spaces are legal in filenames on all modern OSes, they cause problems in shell commands and some legacy tools.

Cross-platform filename best practices

The most reliable filename sanitization strategy is a set of consistent rules applied at every input boundary, rather than a series of ad-hoc fixes that grow over time. These practices prevent `InvalidCharError` and its relatives from appearing in the first place.

Construct filenames from safe components

Wherever possible, generate filenames from controlled inputs rather than passing user-provided strings directly. Build filenames from sanitized identifiers, UUIDs, or timestamps with colons replaced: a UUID like `550e8400-e29b-41d4-a716-446655440000` is already safe on all platforms. If a human-readable name is required, sanitize it first and then append the safe identifier as a suffix to guarantee uniqueness.

Validate at every OS boundary

  • File uploads — sanitize the uploaded filename before saving, even if your web framework provides a filename field
  • API responses — treat any filename field from an external API as untrusted; validate before using
  • Database records — filenames stored in a database may have been saved before your sanitization rules were in place
  • Configuration files — filenames read from config files can be incorrect if the config was edited by a user
  • Command-line arguments — user-supplied path arguments may contain shell expansions or special characters

Test on all target platforms

A filename bug that only manifests on Windows is invisible in a Linux-only development environment. If your application will run on Windows, test your file handling code on Windows — or add a CI job that runs on a Windows runner. The Filename Sanitizer for Cross-Platform Uploads provides an OS-agnostic check you can run from any platform, making it a practical substitute for multi-OS testing during development.

Warning

Do not use `os.path.basename()` alone as a security measure for uploaded filenames. It strips path components but does not sanitize illegal characters. A filename like `../../../etc/passwd` becomes `passwd` after `os.path.basename()` — a path traversal attempt — but `invoice:Q1.pdf` becomes `invoice:Q1.pdf` unchanged. Always apply both path-traversal prevention and character sanitization as separate steps.

Validating filenames before use

A sanitizer that auto-replaces characters is a production safeguard. A validator that checks and reports issues is a development and debugging tool. Both have their place, and using them together gives you the strongest coverage.

What the Filename Sanitizer tool checks

The Filename Sanitizer for Cross-Platform Uploads validates filenames against all three major OS rule sets in one pass. It checks for illegal characters (Windows, macOS, Linux), Windows reserved device names, trailing dots and spaces (illegal on Windows), leading dots (hidden file signal on Unix), null bytes and control characters, and filename length in both characters and UTF-8 bytes. It also shows you the sanitized safe version of the filename alongside the validation report.

Integrating validation into CI

For applications that generate filenames from templates or configurable patterns, add a unit test that validates the generated names against cross-platform rules on every build. A filename template that works in your current environment can produce an `InvalidCharError` after a configuration change that introduces a colon into the pattern. Catching this in CI is significantly less costly than debugging it in production.

Key takeaways

  • `InvalidCharError` fires when a filename contains a character illegal on the target OS — the error message always identifies the specific character.
  • Windows forbids `&lt; &gt; : " / \ | ? *`, control characters, trailing dots/spaces, and reserved names (CON, NUL, COM1-9, LPT1-9).
  • Linux only forbids null bytes and forward slashes — but portable code should apply Windows rules universally.
  • Always sanitize filenames at the input boundary (upload handler, API parser) rather than catching exceptions after the fact.
  • Use the Filename Sanitizer for Cross-Platform Uploads to validate any filename against all three OS rule sets in one pass.
  • Unicode filenames with encoding corruption need the Unicode and Encoding Repair Tool before sanitization.
  • Auto-replace illegal characters with hyphens in upload handlers; raise exceptions in internal code where invalid filenames are a bug to fix.

Frequently Asked Questions

InvalidCharError is an exception raised by the `python-filenamesanitizer` library (and similar filename validation libraries) when a filename string contains one or more characters that are illegal on the target operating system. The error identifies the specific character that caused the rejection. It is most commonly encountered when handling filenames from user uploads, API responses, or external data sources that have not been validated before being passed to filesystem operations.

Windows forbids the following characters in filenames: `< > : " / \ | ? *` and all control characters (Unicode codepoints U+0000 through U+001F). Windows also reserves specific names for system devices: CON, PRN, AUX, NUL, COM1–COM9, and LPT1–LPT9 — these names cannot be used as filenames regardless of extension. Additionally, filenames cannot end with a dot (.) or a space. These rules apply to all Windows filesystems including NTFS and FAT32.

macOS and Linux (POSIX) filesystems are significantly more permissive. The only universally forbidden characters are the null byte (\0) and the forward slash (/). However, filenames beginning with a dot (.) are treated as hidden files, filenames beginning with a hyphen can interfere with command-line argument parsing, and spaces and special shell characters (`, $, !, &, ;, |, and others) create problems in shell scripts even if the OS allows them. For portable code, treat all Windows-illegal characters as off-limits.

You can sanitize filenames with a regular expression and a few string operations. Replace all Windows-illegal characters (`< > : " / \ | ? *`) and control characters with a hyphen or underscore. Strip leading and trailing dots and spaces. Check the result against the Windows reserved name list (CON, PRN, AUX, NUL, COM1-9, LPT1-9) and append a suffix if it matches. Truncate to 255 bytes for NTFS compatibility. This covers the vast majority of cases without requiring a third-party library.

In Django, the recommended approach is to override the `generate_filename()` method on your storage backend or use Django's built-in `get_valid_name()` utility from `django.utils.text`. This function strips characters that are not alphanumeric, dots, underscores, or hyphens. For uploads that may contain Unicode names or non-ASCII characters from international users, run the name through `unicodedata.normalize("NFC", name)` first to normalize composed forms, then apply the sanitizer.

Yes — if the exception is unhandled, the file write operation failed and no file was created on disk. The exception is raised before any data is written. You need to catch the exception, sanitize the filename, and retry the write with the clean name. In a web application, this means wrapping the filename sanitization in a try/except block in your upload handler, applying a fallback sanitizer when the error is caught, and logging the original filename for debugging.

The safest approach is proactive validation before attempting any filesystem operation. Pass the filename through the Filename Sanitizer for Cross-Platform Uploads tool to identify issues during development, and implement a programmatic check in your code using a validation function that tests against all three OS rule sets simultaneously. This is more reliable than catching exceptions after the fact, because some invalid filenames cause silent errors or incorrect behaviour rather than explicit exceptions.

The limit depends on the filesystem. NTFS (Windows) allows 255 UTF-16 code units for the filename component, excluding the path. Most Linux filesystems (ext4, XFS) allow 255 bytes in the filename component. macOS (APFS, HFS+) allows 255 UTF-16 code units. The safe cross-platform limit is 255 bytes. When filenames contain non-ASCII Unicode characters (which encode to 2–4 bytes each in UTF-8), a filename that appears short in characters can exceed 255 bytes — always measure in encoded bytes when enforcing the limit.

ShareXLinkedIn

Related articles