Fix AI Generated Code: Practical Steps for Backend Engineers A backend engineer has outlined a practical workflow for auditing and fixing AI-generated code, warning that AI tools frequently produce code that looks correct but introduces hardcoded secrets, SQL injection through string concatenation, and missing input validation. The guidance recommends parameterized queries, disabling debug modes in production, handling database integrity errors, and adding authentication and Pydantic validation to every AI-generated endpoint before it reaches production. 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.