On this page
  1. The problem: AI generates functional but messy code
  2. The lint rules AI assistants consistently break
  3. The fix: auto-fix in CI (not manually)
  4. Linting as a code review signal
  5. Should you tell the AI to “write lint-clean code”?
  6. The linting pipeline for AI-generated code
  7. Checklist
  8. FAQ
    1. Why does AI-generated code fail linting so often?
    2. Should I run the linter before or after reviewing AI code?
    3. Do I need a linter if I have Prettier?
  9. Related topics
  10. Sources
how-to

Why Does the AI's Code Keep Failing Linting (and How to Fix It)?

Your AI assistant generates code that fails every lint rule. Here's why, which rules to enforce in CI, and how to auto-fix the AI's output before it merges.

Quick answer

  • AI assistants generate code that passes the compiler but fails every lint rule — unused imports, mixed quote styles, line-length violations, trailing whitespace.
  • The fix: run the linter as a CI step (never skip it), auto-fix what you can, and treat lint failures as a review signal — the AI’s messy code often has deeper problems.

The problem: AI generates functional but messy code

Your AI assistant writes code that works. It also writes code that fails eslint, pylint, ruff, prettier, and every other linter with a config file. Why?

AI models are trained on public code — which means code from every era, every style guide, and every level of discipline. The model averages across all of it. The result:

# AI-generated: works, fails lint
import os, sys, json
def getData(x):
   data = { 'name': x }
   unused_var = 42
   return data

The linter complains about:

  • Multiple imports on one line
  • Missing type hints
  • Inconsistent spacing around braces
  • Unused variable unused_var
  • Function name not in snake_case
  • Missing docstring

The code works. But it’s not ready to ship.

The lint rules AI assistants consistently break

RuleWhat the AI doesLinter catch
Unused importsimport json and never use iteslint no-unused-vars, ruff F401
Trailing whitespaceSpaces at end of lines (invisible in editor)Most linters auto-fix
Line length120+ character linespylint line-too-long, eslint max-len
Mixed quotes'single' and "double" in same fileprettier, ruff Q rules
Missing trailing commasInconsistent in multi-line listsprettier, ruff COM rules
Shadowing builtinslist = [...], id = 42pylint redefined-builtin, ruff A001
Bare exceptexcept: instead of except SpecificError:pylint bare-except, ruff E722
Mutable default argsdef f(items=[])pylint dangerous-default-value, ruff B006

The last two aren’t just style — they’re bugs waiting to happen. That’s why linting matters.

The fix: auto-fix in CI (not manually)

You could fix these one at a time. Or you can make the linter do it:

# Python (ruff — fast, auto-fixes most rules)
ruff check --fix .

# JavaScript/TypeScript
eslint --fix .
prettier --write .

# General
pre-commit run --all-files

Run this as a CI step so it’s impossible to merge AI-generated code without linting:

# .github/workflows/ci.yml
- name: Lint
  run: |
    ruff check .
    ruff format --check .

If lint fails, the pipeline fails. The AI’s code doesn’t merge until it’s clean.

Linting as a code review signal

Lint failures on AI-generated code aren’t just noise — they’re signals. When the AI produces a function with 12 lint violations, it often also has deeper problems: duplicated logic, unclear naming, missing error handling. The lint failures are the surface-level indicators of code that needs a closer review.

A clean lint run tells you the AI happened to produce code in the right style. A messy lint run tells you to slow down and read more carefully.

Should you tell the AI to “write lint-clean code”?

You can, and it helps — but not completely. The AI will fix the obvious ones (trailing whitespace, indentation) but miss the ones that require context (unused imports where the import is used elsewhere in a refactored file, mutable default arguments).

A better approach: add your lint rules to the AI’s old prompt. If your project uses ruff:

This project uses ruff for linting with the following rules enabled:
F (Pyflakes), E/W (pycodestyle), I (isort), N (pep8-naming),
B (flake8-bugbear), A (flake8-builtins). Run `ruff check` and
fix any violations before considering the code complete.

This won’t eliminate lint failures, but it’ll reduce them significantly.

The linting pipeline for AI-generated code

AI generates code


Review logic and behavior (you)


Run linter (auto-fix where possible)


Lint errors remain? ──► Fix manually or ask AI to fix specific issues

     ▼ (clean)
Commit

Never skip the review step. Auto-fixing before reviewing means you’re reviewing code that neither you nor the AI wrote — it’s been modified by the linter, and subtle bugs can be introduced.

Where this bites vibecoders

The AI generates a 200-line function that works. The vibecoder tests it manually, it passes, and they ship it. The linter would have caught an unused import, a bare except, and a mutable default argument — two of which are bugs that surface weeks later. Adding ruff check or eslint to CI takes five minutes and catches these automatically.

Checklist

  • Linter runs in CI on every push — fails the pipeline on violations
  • Auto-fix enabled: ruff check --fix or eslint --fix
  • Review AI-generated code before auto-fixing, not after
  • Add lint rules to the AI’s system prompt for better output
  • Treat lint failures on AI code as a signal to read more carefully

FAQ

Why does AI-generated code fail linting so often?

Because training data includes code from every era and every style. The AI averages across PEP 8, Google style, and no style at all. It produces code that works but isn’t consistently formatted: unused imports, trailing whitespace, line-length violations, and mixed quote styles in the same file.

Should I run the linter before or after reviewing AI code?

After — but only for the first review. Once you’ve confirmed the logic is correct, let the linter auto-fix the style. Running the linter before review means you’re reviewing auto-fixed code you didn’t write and the AI didn’t write. Review the AI’s output raw, then auto-fix.

Do I need a linter if I have Prettier?

Prettier handles formatting (spacing, quotes, line width). It does not catch bugs like unused variables, bare excepts, or mutable default args. You need both: a formatter (Prettier/ruff format) and a linter (eslint/ruff check). They solve different problems.


Sources

Share: