Skip to main content

How to Resolve Python Error "ValueError: must have exactly one of create/read/write/append mode"

When opening files in Python using the built-in open() function, you specify a mode string (like 'r', 'w', 'a') to indicate how you intend to interact with the file (read, write, append, etc.). The ValueError: must have exactly one of create/read/write/append mode occurs when you provide an invalid or ambiguous combination of mode characters that Python's open() function doesn't recognize.

This guide explains the valid file modes in Python and provides the correct modes to use, especially when needing both read and write access.

Understanding the Error: File Opening Modes

The second argument to the open(filename, mode) function is the mode string. This tells Python:

  • The primary operation intended (reading, writing, appending, exclusive creation).
  • Whether the file should be handled as text (default) or binary (b).
  • Whether read/write operations should be allowed simultaneously (+).

Python expects the mode string to follow specific combinations. Providing a string like 'rw' is invalid because it ambiguously specifies both 'read' and 'write' as the primary operation. Python needs a single primary operation (r, w, a, or x) optionally followed by modifiers like + or b.

The Cause: Invalid Mode String

The error is triggered when the string passed as the mode argument to open() does not conform to the valid mode combinations defined by Python. Trying to combine primary modes like 'r' and 'w' directly is a common mistake.

Error Scenario (e.g., 'rw')

filename = "my_file.txt"
# Create file if it doesn't exist for demo
with open(filename, 'w') as f: f.write("Initial content.\n")

try:
# ⛔️ ValueError: must have exactly one of create/read/write/append mode
# 'rw' is not a valid mode string.
with open(filename, 'rw', encoding='utf-8') as my_file:
content = my_file.read()
my_file.write("New line.\n")
except ValueError as e:
print(e)

Python rejects 'rw' because it needs a single character (r, w, a, or x) to indicate the base mode, potentially followed by + and/or b.

Solution: Use Valid File Modes

Replace the invalid mode string with one of the officially supported modes based on your needs.

Common Basic Modes ('r', 'w', 'a')

  • 'r' (Read - Default): Opens the file for reading only. Starts at the beginning of the file. Raises FileNotFoundError if the file doesn't exist.
    with open(filename, 'r', encoding='utf-8') as f:
    content = f.read()
    print(f"Read content: {content}")
  • 'w' (Write): Opens the file for writing only. Truncates (erases) the file if it exists. Creates the file if it doesn't exist. Starts at the beginning.
    with open(filename, 'w', encoding='utf-8') as f:
    f.write("This overwrites existing content.\n")
    print("Wrote to file (w mode).")
  • 'a' (Append): Opens the file for writing only. Creates the file if it doesn't exist. Starts writing at the end of the file. Existing content is preserved.
    with open(filename, 'a', encoding='utf-8') as f:
    f.write("This line is appended.\n")
    print("Appended to file (a mode).")

Modes for Reading AND Writing ('r+', 'w+', 'a+')

These modes use the + modifier to allow both input and output operations.

  • 'r+' (Read and Write): Opens for reading and writing. Does not truncate. Starts at the beginning of the file. Raises FileNotFoundError if the file doesn't exist. This is often the correct replacement for the invalid 'rw' attempt.
    with open(filename, 'r+', encoding='utf-8') as f:
    initial_content = f.read() # Reads from start
    print(f"Content before write (r+): {initial_content.strip()}")
    f.write(" --- Added via r+ --- ") # Writes at current position (end after read)
    f.seek(0) # Move back to start
    updated_content = f.read()
    print(f"Content after write (r+): {updated_content.strip()}")
  • 'w+' (Write and Read): Opens for writing and reading. Truncates the file if it exists. Creates the file if it doesn't exist. Starts at the beginning.
    with open(filename, 'w+', encoding='utf-8') as f:
    print("File opened with w+ (truncated).")
    f.write("Content written by w+.\n")
    f.seek(0) # Move back to start to read what was just written
    content = f.read()
    print(f"Content read after write (w+): {content.strip()}")
  • 'a+' (Append and Read): Opens for reading and writing. Creates the file if it doesn't exist. Starts writing at the end of the file. Reading starts from the current position (which is initially the end unless you seek()).
    with open(filename, 'a+', encoding='utf-8') as f:
    print("File opened with a+.")
    f.write(" --- Appended via a+ --- ") # Writes at the end
    f.seek(0) # Move back to start to read everything
    content = f.read()
    print(f"Full content after append (a+): {content.strip()}")

Binary Modes ('rb', 'wb', 'ab', 'rb+', etc.)

Add b to any of the above modes (e.g., 'rb', 'wb+') to open the file in binary mode. This reads/writes bytes objects instead of str objects and performs no encoding/decoding or newline translation. Essential for non-text files (images, executables, etc.).

# Example: Writing bytes
with open('data.bin', 'wb') as f: # Write binary
f.write(b'\x01\x02\x03\x04')
print("Wrote bytes to data.bin")

Exclusive Creation ('x')

  • 'x' (Exclusive Create - Write): Opens for writing only, but only if the file does not already exist. If the file exists, it raises a FileExistsError. Creates the file if it doesn't exist.
  • 'xb', 'x+', 'xb+': Similar variations for binary, read/write combined with exclusive creation.
try:
with open('new_exclusive_file.txt', 'x', encoding='utf-8') as f:
f.write("Created exclusively.")
print("Successfully created exclusive file.")
except FileExistsError:
print("Exclusive file already exists.")

Choosing Between 'r+', 'w+', and 'a+'

  • Use 'r+' when you need to read first and then potentially overwrite parts of an existing file (or write after reading). It won't create the file if missing.
  • Use 'w+' when you want to start with a blank slate (erase existing content or create a new file) and then write and potentially read back what you wrote.
  • Use 'a+' when you want to add content to the end of an existing file (or create it if missing) and also be able to read from it (often requiring seek(0) to read from the beginning).

Conclusion

The ValueError: must have exactly one of create/read/write/append mode occurs when you supply an invalid mode string (like 'rw') to Python's open() function. Python requires a specific, valid combination of mode characters.

To fix this:

  1. Identify your primary goal: Reading (r), Writing (overwrite/create w), Appending (a), or Exclusive Creation (x).
  2. Determine if you also need the opposite operation (reading and writing/appending): Add + (e.g., 'r+', 'w+', 'a+').
  3. Determine if you need binary mode: Add b (e.g., 'rb', 'wb+').
  4. Use one of the valid mode combinations (e.g., 'r', 'w', 'a', 'r+', 'w+', 'a+', 'rb', 'wb', 'ab+', etc.) as the second argument to open().

Using the correct, standard file modes will prevent this ValueError and ensure files are opened with the intended behavior. For reading and writing existing files, 'r+' is often the intended mode when 'rw' was mistakenly used.