Aider-AI/aider · error · ValueError

Invalid line_endings value: {line_endings}. Must be one of:

Error message

Invalid line_endings value: {line_endings}. Must be one of: {', '.join(valid_line_endings)}

What it means

InputOutput.__init__ in aider/io.py validates the line_endings constructor argument against a whitelist {"platform", "lf", "crlf"}. Any other value — including None (unless you match the exact strings), typos like 'CRLF', 'windows', or 'auto' — raises ValueError at construction time, before any I/O happens. The chosen value is later mapped to self.newline (None for platform, \n for lf, \r\n for crlf) which controls how chat/input history files are written.

Source

Thrown at aider/io.py:326

        self.yes = yes

        self.input_history_file = input_history_file
        if self.input_history_file:
            try:
                Path(self.input_history_file).parent.mkdir(parents=True, exist_ok=True)
            except (PermissionError, OSError) as e:
                self.tool_warning(f"Could not create directory for input history: {e}")
                self.input_history_file = None
        self.llm_history_file = llm_history_file
        if chat_history_file is not None:
            self.chat_history_file = Path(chat_history_file)
        else:
            self.chat_history_file = None

        self.encoding = encoding
        valid_line_endings = {"platform", "lf", "crlf"}
        if line_endings not in valid_line_endings:
            raise ValueError(
                f"Invalid line_endings value: {line_endings}. "
                f"Must be one of: {', '.join(valid_line_endings)}"
            )
        self.newline = (
            None if line_endings == "platform" else "\n" if line_endings == "lf" else "\r\n"
        )
        self.dry_run = dry_run

        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.append_chat_history(f"\n# aider chat started at {current_time}\n\n")

        self.prompt_session = None
        self.is_dumb_terminal = is_dumb_terminal()

        if self.is_dumb_terminal:
            self.pretty = False
            fancy_input = False

View on GitHub (pinned to 5dc9490bb3)

Solutions

  1. Pass exactly one of the three accepted strings: 'platform' (use OS default), 'lf', or 'crlf'.
  2. If the value comes from user config, normalize it first: strip whitespace and lowercase it, then check membership before constructing InputOutput.
  3. Map platform names explicitly: 'Windows' -> 'crlf', 'Linux'/'Darwin' -> 'lf', or just use 'platform' to defer to the OS default.

Example fix

# before
io = InputOutput(line_endings="CRLF")  # ValueError: Invalid line_endings value

# after
raw = "CRLF".strip().lower()
line_endings = raw if raw in {"platform", "lf", "crlf"} else "platform"
io = InputOutput(line_endings=line_endings)
Defensive patterns

Strategy: validation

Validate before calling

VALID = {"platform", "lf", "crlf"}

def make_io(line_endings):
    key = str(line_endings).strip().lower()
    if key not in VALID:
        raise ValueError(f"line_endings must be one of {sorted(VALID)}, got {line_endings!r}")
    from aider.io import InputOutput
    return InputOutput(line_endings=key)

Type guard

def is_valid_line_endings(v) -> bool:
    return isinstance(v, str) and v.strip().lower() in {"platform", "lf", "crlf"}

Try / catch

try:
    io = InputOutput(line_endings=le)
except ValueError as e:
    if "Invalid line_endings" in str(e):
        io = InputOutput(line_endings="platform")  # safe default
    else:
        raise

Prevention

When it happens

Trigger: Instantiating InputOutput(line_endings=...) with a string outside the set {'platform','lf','crlf'}. Typical offenders: 'CRLF' (uppercase), 'LF', '\r\n', 'windows', 'unix', 'native', or passing an int/None where a string is expected. It raises immediately in __init__, so the failure occurs at object creation, not during file writes.

Common situations: Programmatically embedding aider's IO class in another tool and deriving line_endings from a config enum (e.g. LineEndings.CRLF.name yielding 'CRLF') or from platform.system() output ('Windows' instead of 'crlf'). Interactive CLI users rarely hit it because aider's own args pass one of the three valid literals.

Related errors


AI-assisted analysis of Aider-AI/aider@5dc9490bb3 (2026-08-15). Data as JSON: /api/errors/5dd686796081a14c. Report an issue: GitHub.