Skip to content

How to Resolve Python "_csv.Error: iterator should return strings, not bytes"

Fix the _csv.Error in Python by opening CSV files in text mode ('r') with the correct encoding (e.g., 'utf-8') instead of binary mode ('rb').

When reading or processing CSV (Comma Separated Values) files in Python using the built-in csv module, you might encounter the _csv.Error: iterator should return strings, not bytes (the file should be opened in text mode). This error indicates a fundamental mismatch between how the file was opened and what the csv module expects as input.

This guide explains why the csv module requires text input and provides the standard solutions to fix this error by opening files correctly.

Understanding the Error: csv Module Expects Text (Strings)

The csv module in Python is designed to work with text data. Its purpose is to interpret rows and columns based on delimiters (like commas) and quoting rules within textual content. It needs to read the file content as strings (str) to correctly identify these delimiters and parse the fields.

Binary mode ('rb'), on the other hand, reads the raw bytes (bytes) from the file without interpreting them as text based on any encoding. The csv reader cannot reliably process raw bytes to find delimiters and structure, leading to the _csv.Error.

The Cause: Opening the CSV File in Binary Mode ('rb')

The error occurs when you pass a file object that was opened in binary read mode ('rb') to a csv.reader or csv.DictReader.

import csv


try:
    with open('data.csv', mode='rb') as csvfile:
        csv_reader = csv.reader(csvfile, delimiter=',')
        for row in csv_reader:
            print(row)
except csv.Error as e:
    print(f"Error: {e}")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

with open('data.csv', 'w', newline='', encoding='utf-8') as f:
    f.write('name,value\napple,10\nbanana,5')

The csv.reader receives byte sequences like b'name,value\n' which it cannot process as delimited text.

The correct and standard solution is to open the CSV file in text mode. This ensures that the file content is read and decoded into strings before being passed to the csv module.

Using mode='r' with encoding

Opening with mode='r' (read mode) defaults to text mode. It is crucial to specify the correct encoding (like 'utf-8', which is very common) when working in text mode to ensure bytes are correctly decoded into characters.

import csv

filename = 'data.csv'

try:
    with open(filename, mode='r', encoding='utf-8', newline='') as csvfile:
        print(f"File '{filename}' opened successfully in text mode.")
        csv_reader = csv.reader(csvfile, delimiter=',')
        print("CSV Reader created. Reading rows:")
        for row in csv_reader:
            print(row)
        print("Finished reading.")
except FileNotFoundError:
    print(f"Error: File '{filename}' not found.")
except Exception as e:
    print(f"An error occurred: {e}")

Example Output:

File 'data.csv' opened successfully in text mode.
CSV Reader created. Reading rows:
['name', 'value']
['apple', '10']
['banana', '5']
Finished reading.
  • mode='r': Opens the file for reading text. mode='rt' is equivalent and more explicit but less common.
  • encoding='utf-8': Specifies how to decode the bytes from the file into strings. Replace 'utf-8' if your file uses a different encoding (e.g., 'latin-1', 'cp1252').
  • newline='':** Recommended when working with the csv module to prevent issues with how different operating systems handle line endings (\n, \r\n). The csv module handles line endings internally.

Default Mode ('r')

If you omit the mode argument entirely, open() defaults to 'r' (text read mode). However, explicitly specifying 'r' and especially encoding is strongly recommended for clarity and correctness.

import csv

filename = 'data.csv'
try:
    with open(filename, encoding='utf-8', newline='') as csvfile:
        csv_reader = csv.reader(csvfile)
        for row in csv_reader:
            print(row)
except Exception as e:
    print(f"Error: {e}")

Using with open() (Best Practice)

Using the with open(...) as ...: statement is the recommended way to work with files. It ensures the file is automatically closed even if errors occur within the block. All examples above use this pattern.

Using open() Directly (Requires close())

If you use open() directly without with, you must remember to manually close the file using csvfile.close() to release system resources.

import csv

filename = 'data.csv'
csvfile = None # Initialize variable
try:
    csvfile = open(filename, mode='r', encoding='utf-8', newline='')
    csv_reader = csv.reader(csvfile)
    for row in csv_reader:
        print(row)
except Exception as e:
    print(f"Error: {e}")
finally:
    if csvfile:
        csvfile.close()
        print(f"\nFile '{filename}' closed.")

The with statement is generally preferred as it's less error-prone than manual closing.

Solution 2: Using codecs.iterdecode (Less Common)

If you have a binary stream (e.g., from a network request or a file already opened in binary mode) that you need to process as CSV, you can use the codecs module to decode the byte stream into a string stream before passing it to csv.reader. This is less common than simply opening the file in text mode initially.

import csv
import codecs

filename = 'data.csv'

try:
    with open(filename, mode='rb') as binary_file:
        print(f"File '{filename}' opened in binary mode.")
        text_stream = codecs.iterdecode(binary_file, encoding='utf-8')
        csv_reader = csv.reader(text_stream, delimiter=',')
        print("Decoding stream and reading rows:")
        for row in csv_reader:
            print(row)
        print("Finished reading via codecs.")
except FileNotFoundError:
    print(f"Error: File '{filename}' not found.")
except Exception as e:
    print(f"An error occurred: {e}")
  • codecs.iterdecode(binary_file, encoding='utf-8'): Wraps the binary file object, yielding decoded strings using the specified encoding.
  • csv.reader(text_stream, ...): The reader now correctly receives strings.

This ValueError occurs if you mistakenly provide the encoding argument to open() when the mode is set to binary ('rb', 'wb', 'ab', etc.). Encoding is only relevant for text modes ('r', 'w', 'a', 'rt', etc.).

try:
    with open('somefile.bin', mode='rb', encoding='utf-8') as f:
        pass
except ValueError as e:
    print(e)

Solution: Remove the encoding argument when using binary modes. If you need encoding, use a text mode like 'r'.

Conclusion

The _csv.Error: iterator should return strings, not bytes clearly indicates that you provided byte data (from opening a file in 'rb' mode) to Python's csv module, which strictly requires text data (strings).

The standard and recommended solution is to open your CSV file in text mode (mode='r') and explicitly specify the correct file encoding (e.g., encoding='utf-8'):

import csv

with open('your_file.csv', mode='r', encoding='utf-8', newline='') as csvfile:
    reader = csv.reader(csvfile)
    for row in reader:
        print(row)

Using codecs.iterdecode is a viable alternative if you must work with an existing binary stream, but opening directly in text mode is usually simpler.

Navigation