# Resolving ESLint Warnings and Errors in Lovable Code

- Tool: Lovable
- Difficulty: Advanced
- Fix time: ~15 min
- Compatibility: All Lovable projects with ESLint configured
- Last updated: March 2026

## TL;DR

ESLint warnings in Lovable-generated code come from unused variables, missing useEffect dependencies, React hooks rule violations, and implicit any types. Fix them by removing unused imports, completing dependency arrays, following the Rules of Hooks (never call hooks conditionally), and adding explicit TypeScript types. Prefix intentionally unused parameters with an underscore (_event) to suppress warnings without disabling the rule.

## Why ESLint warnings appear in Lovable-generated code

Lovable's AI generates functional code, but ESLint applies stricter standards than just 'works correctly.' The AI may declare variables it does not end up using, import components it later decides not to include, or write useEffect hooks with incomplete dependency arrays. These are not bugs that break your app, but they indicate code quality issues that can lead to real bugs later.

The most impactful ESLint warnings in Lovable code are the React hooks rules. Calling a hook inside a conditional statement, a loop, or a nested function breaks React's internal state tracking and causes unpredictable behavior. The exhaustive-deps rule for useEffect prevents stale closure bugs that are among the hardest to debug.

While it is tempting to disable ESLint rules that produce many warnings, most rules exist for good reasons. The better approach is to fix the warnings or, for intentionally unused parameters, use the underscore prefix convention to communicate intent.

- Lovable generates import statements for components it does not end up using in the final code
- useEffect dependency arrays are incomplete, triggering the exhaustive-deps rule
- Hooks are called inside conditional blocks, violating the Rules of Hooks
- TypeScript strict mode is not enabled, so implicit any types are widespread
- Variables are declared in one generation step but the code that uses them is generated in a later step

## Error messages you might see

**'useState' is defined but never used**

The component imports useState but never calls it. Either the AI generated an unused import, or the state was removed in a later edit. Delete the unused import.

**React Hook useEffect has a missing dependency: 'fetchData'**

The useEffect calls fetchData but it is not in the dependency array. Add fetchData to the array, or move the function definition inside the effect.

**React Hook 'useState' is called conditionally. React Hooks must be called in the exact same order in every component render.**

A useState or useEffect call is inside an if statement. Hooks must always be called at the top level of the component. Move the hook outside the conditional and use the condition inside the hook's logic.

**'any' is not allowed as a type annotation**

TypeScript's no-explicit-any rule is enabled. Replace 'any' with a specific type. If the type is unknown, use 'unknown' and narrow it with type guards.

## Before you start

- A Lovable project with ESLint warnings visible in Dev Mode or the browser console
- Basic understanding of React hooks (useState, useEffect, useCallback)
- Access to the Lovable editor for fixing the warnings

## How to fix it

### 1. Remove unused variables and imports

*Unused code adds clutter and can mask real issues — ESLint flags it to keep the codebase clean*

Find all ESLint warnings about unused variables and imports. For each one, determine if the variable is truly unused or if it is needed but the code referencing it is missing. Delete imports that are not referenced anywhere in the file. For function parameters that are required by an interface but not used in your implementation, prefix them with an underscore: (_event) instead of (event).

Before:

```
import { useState, useEffect, useCallback } from "react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card"; // Never used

const MyComponent = () => {
  const [count, setCount] = useState(0); // count never read
  const data = fetchData(); // data never used
  return <Button>Click</Button>;
};
```

After:

```
import { Button } from "@/components/ui/button";
// Removed: useState, useEffect, useCallback, Card (all unused)

const MyComponent = () => {
  // Removed: unused count state and data variable
  return <Button>Click</Button>;
};
```

**Expected result:** No more 'defined but never used' warnings. The code only contains imports and variables that are actually referenced.

### 2. Fix missing useEffect dependencies

*Missing dependencies cause stale closures where the effect uses outdated values from a previous render*

For each 'missing dependency' warning, add the missing variable to the dependency array. If adding it causes the effect to run too often, restructure: move functions inside the effect, wrap functions in useCallback, or use functional setState to avoid depending on the state variable.

Before:

```
const [userId, setUserId] = useState("1");
const [data, setData] = useState(null);

// Warning: missing dependency 'userId'
useEffect(() => {
  fetch(`/api/users/${userId}`).then(r => r.json()).then(setData);
}, []);
```

After:

```
const [userId, setUserId] = useState("1");
const [data, setData] = useState(null);

// Fixed: userId in dependency array
useEffect(() => {
  let cancelled = false;
  fetch(`/api/users/${userId}`)
    .then(r => r.json())
    .then(d => { if (!cancelled) setData(d); });
  return () => { cancelled = true; };
}, [userId]);
```

**Expected result:** No more exhaustive-deps warnings. The effect re-runs when userId changes and properly handles cleanup.

### 3. Fix React Hooks rule violations

*Calling hooks conditionally breaks React's internal state tracking and causes unpredictable bugs*

React requires that hooks are called in the exact same order on every render. If a hook is inside an if statement, it only runs on some renders, breaking this rule. Move the hook to the top level and put the conditional logic inside the hook's callback or after the hook call. This is a hard rule — there is no workaround other than restructuring the code.

Before:

```
const MyComponent = ({ showCounter }: { showCounter: boolean }) => {
  // Error: hook called conditionally
  if (showCounter) {
    const [count, setCount] = useState(0);
    return <button onClick={() => setCount(count + 1)}>{count}</button>;
  }
  return <p>No counter</p>;
};
```

After:

```
const MyComponent = ({ showCounter }: { showCounter: boolean }) => {
  // Fixed: hook always called at top level
  const [count, setCount] = useState(0);

  if (!showCounter) {
    return <p>No counter</p>;
  }

  return <button onClick={() => setCount((prev) => prev + 1)}>{count}</button>;
};
```

**Expected result:** No more 'hooks called conditionally' error. The hook is always called, and the conditional logic is below it.

### 4. Replace any types with specific TypeScript types

*Explicit types catch bugs at compile time and make the code self-documenting*

Find all instances of the any type and replace them with specific types. For API responses, define an interface. For event handlers, use React's built-in types like React.ChangeEvent<HTMLInputElement>. For truly unknown data, use the unknown type with type guards to narrow it safely. If fixing types across a large generated codebase involves understanding complex type hierarchies, RapidDev's engineers have done this across 600+ Lovable projects.

Before:

```
const handleSubmit = (data: any) => {
  const result: any = processData(data);
  setItems(result.items as any[]);
};
```

After:

```
type FormData = {
  name: string;
  email: string;
};

type ProcessResult = {
  items: string[];
  total: number;
};

const handleSubmit = (data: FormData) => {
  const result: ProcessResult = processData(data);
  setItems(result.items);
};
```

**Expected result:** No more 'any' type warnings. TypeScript can now catch type errors at compile time.

## Complete code example

File: `src/components/CleanComponent.tsx`

```typescript
import { useState, useEffect } from "react";
import { Button } from "@/components/ui/button";

// Specific type instead of 'any'
type User = {
  id: string;
  name: string;
  email: string;
};

type CleanComponentProps = {
  userId: string;
  onSelect?: (user: User) => void;
};

const CleanComponent = ({ userId, onSelect }: CleanComponentProps) => {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);

  // All dependencies included, cleanup function present
  useEffect(() => {
    let cancelled = false;
    setLoading(true);

    fetch(`/api/users/${userId}`)
      .then((res) => res.json())
      .then((data: User) => {
        if (!cancelled) {
          setUser(data);
          setLoading(false);
        }
      })
      .catch(() => {
        if (!cancelled) setLoading(false);
      });

    return () => { cancelled = true; };
  }, [userId]); // userId is the only dependency

  // Intentionally unused parameter prefixed with _
  const handleKeyDown = (_event: React.KeyboardEvent) => {
    // Handler structure needed for accessibility
  };

  if (loading) return <p>Loading...</p>;
  if (!user) return <p>User not found</p>;

  return (
    <div className="space-y-4" onKeyDown={handleKeyDown}>
      <h2 className="text-xl font-bold">{user.name}</h2>
      <p className="text-muted-foreground">{user.email}</p>
      {onSelect && (
        <Button onClick={() => onSelect(user)}>Select User</Button>
      )}
    </div>
  );
};

export default CleanComponent;
```

## Best practices

- Remove unused imports and variables immediately — they accumulate quickly in AI-generated code
- Never suppress the exhaustive-deps ESLint warning — fix the dependency issue instead
- Prefix intentionally unused parameters with underscore (_event, _index) to suppress warnings without disabling rules
- Always call React hooks at the top level of the component — never inside conditionals, loops, or nested functions
- Define TypeScript types for all function parameters and return values instead of using any
- Use the unknown type instead of any when the type is genuinely unknown — it forces type narrowing
- Configure ESLint rules as warnings during development and errors in production builds
- Ask Lovable to fix ESLint warnings as a dedicated prompt rather than mixing with feature requests

## Frequently asked questions

### Why does Lovable generate code with ESLint warnings?

Lovable's AI focuses on making functional code quickly. It may import components it does not end up using, leave dependency arrays incomplete, or use any types for speed. These do not break the app but reduce code quality. Fix them as a separate cleanup step.

### How do I fix the 'missing dependency' warning in useEffect?

Add the missing variable to the dependency array. If that causes the effect to run too often, restructure: move functions inside the effect, wrap them in useCallback, or use functional setState to avoid depending on the state variable directly.

### Can I disable ESLint rules I do not agree with?

You can, but most React-specific rules exist to prevent real bugs. The exhaustive-deps and hooks rules are particularly important. If you must disable a rule, use eslint-disable-next-line with a comment explaining why, not a blanket rule-off.

### How do I handle unused function parameters?

If a parameter is required by a type or interface but not used in your implementation, prefix it with an underscore: (_event, _index, _unused). This tells ESLint the omission is intentional. Configure the rule: @typescript-eslint/no-unused-vars with argsIgnorePattern: '^_'.

### Should I fix ESLint warnings or build features first?

Build features first, then fix warnings as a cleanup step. ESLint warnings do not break functionality. However, do not let warnings accumulate too long — the exhaustive-deps warnings in particular can mask real stale state bugs.

### What if I can't fix this myself?

If your project has many ESLint errors across dozens of files and fixing them requires understanding TypeScript types and React hook rules, RapidDev's engineers can clean up the entire codebase. They have resolved ESLint issues across 600+ Lovable projects.

---

Source: https://www.rapidevelopers.com/lovable-issues/resolving-eslint-warnings-and-errors-in-lovable-code
© RapidDev — https://www.rapidevelopers.com/lovable-issues/resolving-eslint-warnings-and-errors-in-lovable-code
