# Fix AI Generated Code: Practical Steps for Backend Engineers

> Source: <https://dev.to/ayush_kumar_085a0f2c54e3f/fix-ai-generated-code-practical-steps-for-backend-engineers-47eg>
> Published: 2026-09-14 05:46:25+00:00

Fix AI generated code by starting with what you can see: broken endpoints, silent failures, or security warnings. I’ve been bitten by this more times than I can count - AI tools spit out code that looks right but fails in production. Here’s how to find and fix the real issues.

The most common vulnerabilities I see are hardcoded secrets, SQL injection via string concatenation, and missing input validation. AI often pulls patterns from public repos without understanding context. For example, it might generate a login endpoint like this:

``` python
@app.post("/login")
def login(username: str, password: str):
    query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
    return db.execute(query).fetchone()
```

This is an SQL injection waiting to happen. Never trust user input in a query string. Fix it by using parameterized queries with SQLAlchemy:

``` python
@app.post("/login")
def login(username: str, password: str):
    stmt = text("SELECT * FROM users WHERE username=:username AND password=:password")
    return db.execute(stmt, {"username": username, "password": password}).fetchone()
```

Another frequent issue is leaving debug modes on or exposing internal errors. AI doesn’t know your deployment setup. Always override defaults in production:

```
# In your FastAPI app setup
app = FastAPI(debug=False)  # Never True in prod
```

Detect logic errors by writing tests that mirror real user flows, not just unit tests on functions. AI often gets the “what” right but misses the “when” and “why.” For example, it might generate a user creation endpoint that doesn’t handle duplicate emails:

``` python
@app.post("/users")
def create_user(user: UserCreate):
    db_user = UserModel(**user.dict())
    db.add(db_user)
    db.commit()
    return db_user
```

This will crash on duplicate email if your DB has a unique constraint. Instead, catch the integrity error:

``` python
from sqlalchemy.exc import IntegrityError

@app.post("/users")
def create_user(user: UserCreate):
    db_user = UserModel(**user.dict())
    db.add(db_user)
    try:
        db.commit()
    except IntegrityError:
        db.rollback()
        raise HTTPException(status_code=400, detail="Email already registered")
    return db_user
```

Write a test that tries to create two users with the same email. If it passes, your logic holds. I use Pytest with fixtures to isolate DB state:

``` python
def test_duplicate_email_rejected(client, db_session):
    client.post("/users", json={"email": "a@b.com", "password": "x"})
    response = client.post("/users", json={"email": "a@b.com", "password": "y"})
    assert response.status_code == 400
    assert "Email already registered" in response.json()["detail"]
```

Fix security flaws by assuming every AI-generated endpoint is insecure until proven otherwise. Start with authentication, then input validation, then rate limiting. AI often skips auth entirely or uses fake tokens.

Here’s a typical AI-generated endpoint missing auth:

``` python
@app.get("/data")
def get_data():
    return {"sensitive": "info"}
```

Add real auth using FastAPI’s dependencies. I use JWT with a simple verification function:

``` python
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

security = HTTPBearer()

def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
    token = credentials.credentials
    # In real life: verify signature, expiry, etc.
    if token != "valid-token-for-demo":
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token",
        )
    return token

@app.get("/data")
def get_data(token: str = Depends(verify_token)):
    return {"sensitive": "info"}
```

Then validate inputs with Pydantic. Never accept raw dicts. AI often does this:

``` python
@app.post("/update")
def update_item(data: dict):  # Bad
    return {"received": data}
```

Fix it with a model:

``` python
from pydantic import BaseModel

class UpdateItem(BaseModel):
    item_id: int
    value: str

@app.post("/update")
def update_item(item: UpdateItem):
    return {"updated": item.item_id}
```

This catches malformed JSON early and documents your API.

Validate SQLAlchemy models by checking constraints, relationships, and migrations. AI often creates models without nullable defaults, wrong cascade rules, or missing indexes. I once saw a model where `created_at` had no default and wasn’t indexed - causing slow queries and NULL errors.

Here’s a risky AI-generated model:

```
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    email = Column(String)  # No unique, no index
    password = Column(String)
```

Fix it by adding constraints and indexes that match your business rules:

```
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    email = Column(String, unique=True, index=True, nullable=False)
    password = Column(String, nullable=False)
    created_at = Column(DateTime, server_default=func.now(), nullable=False)
```

Use Alembic to generate migrations after you fix the model. Then run them in a staging DB before deploying. Never skip this step - AI doesn’t know your schema evolution.

Test API contracts by treating your OpenAPI spec as the source of truth. AI often generates endpoints that don’t match the declared schema - missing fields, wrong types, or extra keys. I use Pytest to validate responses against the schema.

First, generate your OpenAPI JSON:

```
curl http://localhost:8000/openapi.json > openapi.json
```

Then write a test that checks every endpoint:

``` python
import jsonschema
import json

with open("openapi.json") as f:
    OPENAPI_SCHEMA = json.load(f)

def test_api_matches_schema(client):
    for path, path_item in OPENAPI_SCHEMA["paths"].items():
        for method, operation in path_item.items():
            if method.lower() in ["get", "post", "put", "delete", "patch"]:
                response = client.request(method, path)
                jsonschema.validate(
                    instance=response.json(),
                    schema=operation["responses"]["200"]["content"]["application/json"]["schema"]
                )
```

This catches mismatches early. If AI adds a field not in the schema, the test fails. If it omits a required one, same thing. It’s saved me from silent data corruption more than once.

Refactor AI-generated async code by removing blocking calls and ensuring proper error propagation. AI often mixes sync and async or forgets to await. I’ve seen endpoints that call `time.sleep(5)` inside an async function - destroying concurrency.

Here’s a bad example:

``` python
@app.get("/slow")
async def slow_endpoint():
    time.sleep(2)  # Blocking!
    return {"done": True}
```

Fix it by using `asyncio.sleep` if you need a delay, or better - remove the delay entirely. For real work like HTTP calls, use `httpx.AsyncClient`:

``` python
import httpx

@app.get("/fetch")
async def fetch_external():
    async with httpx.AsyncClient() as client:
        resp = await client.get("https://api.example.com/data")
        return resp.json()
```

Also, watch for missing `try/except` blocks. AI often omits error handling in async code. Wrap external calls:

``` python
@app.get("/fetch")
async def fetch_external():
    try:
        async with httpx.AsyncClient() as client:
            resp = await client.get("https://api.example.com/data")
            resp.raise_for_status()
            return resp.json()
    except httpx.RequestError as e:
        raise HTTPException(status_code=502, detail=f"External error: {str(e)}")
```

Finally, use logging instead of `print`. AI loves `print` - it’s useless in production. Use structlog or Python’s logging module with JSON output.

Don’t trust AI generated code for authentication, payment processing, or any code handling PII. I’ve seen AI generate OAuth flows that skipped state validation - critical for security. For those, use battle-tested libraries like `fastapi-users` or `python-jose` and read the docs.

Also, avoid using AI to generate migration scripts. Schema changes are too risky. Write them yourself or use Alembic’s autogenerate with careful review.

AI is great for boilerplate, repetitive CRUD, or getting unstuck on a tricky algorithm. But production systems need human judgment. Treat AI output like a junior engineer’s first draft: review it, test it, and break it on purpose.

If you’re stuck fixing AI generated code in your FastAPI or data stack, I’ve helped indie builders do this exact work. You can [hire me](https://www.logiclooptech.dev/hire/) to audit your endpoints, write tests, and make your AI-generated code production ready - no fluff, just fixes.

Look for string concatenation with user input in SQL queries. If you see `f"SELECT ... {user_input}"` or `+ user_input +`, it’s vulnerable. Fix it with parameterized queries or ORM methods.

Not safely. AI often misses token validation, scope checks, or refresh token handling. Use a trusted library and have AI only generate non-critical parts like route stubs or response models.

Run it through a linter like `ruff` or `flake8`, then write a test that exercises the happy path and one edge case. If it passes both, it’s likely safe for low-risk code.

No. Migrations alter your data schema. A mistake can corrupt or lose data. Write them manually, test them in a copy of production, and review every line.
