Quick Answer
Errno 22 means the operating system rejected an argument. Read the traceback, inspect the exact path, mode, timestamp, or handle state, and normalize the argument for the current platform instead of catching and ignoring every OSError.

OSError: [Errno 22] Invalid argument means Python passed an argument to the operating system that the OS rejected. In file-handling code, the usual causes are invalid path text, unsupported filename characters, a bad file mode, a closed file handle, or a platform-specific rule that the code did not check first.
The exact trigger depends on the operating system and the operation. A path that works on Linux may fail on Windows. A timestamp that contains colons can be fine as display text but unsafe as a Windows filename. A file handle that has already been closed cannot be read or written again.
The official Python documentation covers OSError, the errno module, pathlib, and os.path.
Start with the traceback line. Identify the function call that failed and print the path, mode, or object state just before that call. The fix is rarely to catch every OSError and ignore it. The fix is to make the argument valid for the operation and platform.
The examples below avoid unsafe writes and platform-dependent crashes. They show how to inspect errno.EINVAL, clean file names, validate modes, and avoid using closed handles.
Recognize errno EINVAL
Errno 22 is represented by errno.EINVAL. You can compare an exception’s errno field when handling a specific invalid-argument case.
import errno
try:
raise OSError(errno.EINVAL, "Invalid argument")
except OSError as error:
print(error.errno == errno.EINVAL)
print(error.strerror)
This example raises the error deliberately so the handling is deterministic. In real code, inspect the original failing call instead of raising your own exception.
Only catch the specific case you know how to repair. Other OSError values may mean missing files, permission problems, disk issues, or interrupted system calls.

Clean Unsafe Filename Text
Characters allowed in file names differ by platform. A conservative cleanup step can replace common unsafe characters before building a path.
from pathlib import Path
unsafe = 'report:2026/07/10?.txt'
blocked = '<>:"/\\|?*'
translation = str.maketrans({char: "_" for char in blocked})
safe_name = unsafe.translate(translation)
path = Path("exports") / safe_name
print(safe_name)
print(path.as_posix())
This does not create the file. It shows how the final path text changes before any filesystem operation. In production code, also limit length and reject empty names after cleanup.
Use Path objects for path construction instead of manually joining strings with slashes. That keeps separators and parent directories easier to review.

Make Timestamp Filenames Safe
Datetime text often contains colons, which can be invalid in Windows filenames. Format timestamps with safe separators when they will become filenames.
from datetime import datetime
stamp = datetime(2026, 7, 10, 14, 5, 30)
display_text = stamp.isoformat(timespec="seconds")
filename_text = stamp.strftime("%Y-%m-%d_%H-%M-%S")
print(display_text)
print(f"backup-{filename_text}.txt")
Use the human-readable ISO text in logs or page output, but use filename-safe text for paths. Keeping those two formats separate prevents accidental invalid path names.
This is one of the most common causes of Errno 22 in scripts that save reports, screenshots, data exports, or backups with time-based names.
Validate File Modes
An unsupported mode string can trigger a value error before or during file opening. Validate mode text from configuration before passing it to open().
allowed_modes = {"r", "w", "a", "x", "rb", "wb", "ab"}
def validate_mode(mode):
if mode not in allowed_modes:
raise ValueError(f"unsupported file mode: {mode}")
return mode
for mode in ["w", "read"]:
try:
print(validate_mode(mode))
except ValueError as error:
print(error)
This fails early with a clear message when the mode is not part of the accepted set. Adjust the accepted modes for your application rather than accepting arbitrary text.
Clear validation is easier to debug than letting a low-level file call fail later with a broad operating-system error.

Do Not Use A Closed File Handle
Using a file object after it has closed can lead to I/O errors. Keep reads and writes inside the with block that owns the handle.
from tempfile import TemporaryDirectory
from pathlib import Path
with TemporaryDirectory() as folder:
path = Path(folder) / "notes.txt"
with path.open("w", encoding="utf-8") as handle:
handle.write("ready\n")
print(handle.closed)
print(path.read_text(encoding="utf-8").strip())
The handle is closed after the with block, so later code reads through Path.read_text() instead of reusing the closed handle.
If you need several writes, keep them inside the same context block or open the file again with the intended mode.

Check Paths Before Calling OS Functions
Small validation helpers can catch empty path text, embedded null bytes, and path values that are not strings or path-like objects.
from os import PathLike
def validate_path_text(path):
if not isinstance(path, (str, PathLike)):
raise TypeError("path must be text or path-like")
text = str(path)
if not text:
raise ValueError("path must not be empty")
if "\x00" in text:
raise ValueError("path must not contain null bytes")
return text
for candidate in ["report.txt", "", "bad\x00name"]:
try:
print(validate_path_text(candidate))
except (TypeError, ValueError) as error:
print(error)
This helper does not prove that a file exists or that every platform accepts the final path. It catches common bad inputs before they reach filesystem calls.
In short, fix Errno 22 by checking the exact argument passed to the failing call. Clean filenames, use safe timestamp formats, validate modes, keep file handles inside their context blocks, and handle errno.EINVAL only when the repair path is specific and tested.
Log the Argument You Actually Pass
The same error number can come from different operations. Capture a safe representation of the path, mode, and object state immediately before the failing call, then compare the rule for the operating system you are using.
from pathlib import Path
import re
name = 'report:2026.txt'
safe_name = re.sub(r'[<>:"/\\|?*]', '_', name)
path = Path('output') / safe_name
print(path)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text('ready', encoding='utf-8')
Do not blindly sanitize every value: filenames, timestamps, file modes, and closed handles have different constraints. Fix the argument at the boundary where it becomes invalid and preserve the original error context.
For filesystem-related cases, compare Windows path-length handling and shutil.rmtree() before changing a path or deleting a directory.
Frequently Asked Questions
What does OSError Errno 22 mean?
It means an operating-system call received an invalid argument. The exact cause depends on the operation and platform, so inspect the traceback and the values passed to that call.
Why can a filename work on Linux but fail on Windows?
Operating systems allow different filename characters and path rules. Normalize names for the target platform and avoid using display timestamps with unsafe characters as filenames.
Should I catch OSError and ignore errno 22?
No. Catch the specific case only when you have a documented repair. Ignoring it can hide invalid paths, modes, closed handles, or other data-loss risks.
How do I identify errno 22 in code?
Compare the exception’s errno attribute with errno.EINVAL, then inspect the exact call and its arguments. Other OSError values may indicate permissions, missing files, or disk failures.
Thankyou!! helped a lot