5 Common Slop Fixes
AI is a great intern, but a terrible architect. Here is how our experts resolve the most common blockers founders face when scaling AI-built apps.
The LLM 'Infinite Fix' Loop
AI keeps adding more 'useEffect' hooks and 'useState' calls to fix a hydration error, resulting in a 2000-line component that crashes on mount.
useEffect(() => {
setLoading(true);
// LLM adds this to fix the previous bug
if (data) {
setFilteredData(data.filter(i => i.id === id));
// And this...
setLoading(false);
}
}, [data, id, loading]); // Infinite loop trigger// Human Fix: Architectural reasoning // 1. Move filtering logic to useMemo // 2. Remove redundant state sync const filteredData = useMemo(() => data?.filter(i => i.id === id) || [] , [data, id]);
The 'Client-Side' Security Guard
AI implemented 'Admin' protection by hiding a button in the UI, but left the API routes completely exposed to anyone with a token.
// AdminPanel.tsx
{user.role === 'admin' ? <DeleteButton /> : null}
// api/delete-user.ts (AI generated)
export async function POST(req) {
const { id } = await req.json();
await db.users.delete(id);
return Response.json({ success: true });
}// Human Fix: Security Audit
// Implement server-side RLS or Middleware checks
const { data: { user } } = await supabase.auth.getUser();
const { data: profile } = await supabase
.from('profiles')
.select('role')
.eq('id', user.id)
.single();
if (profile?.role !== 'admin') {
return new Response("Unauthorized", { status: 401 });
}The State Management 'Soup'
Prop drilling 15 levels deep because the AI didn't suggest a Context provider or a proper store, making 'one small change' impossible.
<Header user={user} theme={theme} config={config} />
<Sidebar user={user} theme={theme} config={config} />
<Content user={user} theme={theme} config={config} />// Human Fix: Structural Clean-up
// Centralize global state in a lightweight provider
export const AppContext = createContext<AppState>(null!);
export function AppProvider({ children }) {
const state = useAppState(); // Custom hook logic
return (
<AppContext.Provider value={state}>
{children}
</AppContext.Provider>
);
}The Exposed .env Leak
AI suggested hardcoding an API key for 'testing' and the founder accidentally pushed it to a public repo.
const stripe = new Stripe('sk_test_51Mz...');
// Hardcoded in component file// Human Fix: Dev-Ops Recovery // 1. Revoke key immediately // 2. Move to environment variables // 3. Add to .gitignore const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
The 'Janky' Hydration Shift
AI used random 'window' checks inside the component body, causing the layout to jump and flash white before the theme loads.
const theme = typeof window !== 'undefined'
? localStorage.getItem('theme')
: 'light';
return <div className={theme}>...</div>;// Human Fix: UI Polish
// Use a ThemeProvider with hydration-safe rendering
const { resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return <div className="invisible" />;