|
| 1 | +[简体中文](./aider.md) | **English** |
| 2 | + |
| 3 | +# Aider Pitfalls |
| 4 | + |
| 5 | +> Aider's pitfalls differ from IDE-based tools: auto-commit, manual `/add /drop`, multi-model switching — every mechanism can bite. 7 real traps. |
| 6 | +> |
| 7 | +> Hit a new one? Open an Issue or PR. |
| 8 | +
|
| 9 | +--- |
| 10 | + |
| 11 | +## Pitfall 1: Auto-Commit Swallows Your Working Tree Changes |
| 12 | + |
| 13 | +**Symptom** |
| 14 | +- You have uncommitted changes across several files |
| 15 | +- You ask Aider to modify an unrelated file |
| 16 | +- After generating code, it auto-commits — and **your unstaged changes get bundled into that commit** |
| 17 | + |
| 18 | +**Cause** |
| 19 | +Aider defaults to `auto-commits: true`. Its commit scope is the entire working tree diff — it doesn't distinguish "yours" from "mine." It assumes "change = commit." |
| 20 | + |
| 21 | +**Recovery** |
| 22 | +```bash |
| 23 | +git reset HEAD~1 # Undo last commit, files back to working tree |
| 24 | +git status # Separate yours from Aider's |
| 25 | +# Manually commit what should be committed, discard the rest |
| 26 | +``` |
| 27 | + |
| 28 | +**Prevention** |
| 29 | +Pick one: |
| 30 | +1. **`git stash` before the session**: hide your WIP so Aider's commit stays clean |
| 31 | +2. **Disable auto-commit**: `aider --no-auto-commits`, or `auto-commits: false` in `.aider.conf.yml` |
| 32 | +3. **Dedicated branch**: `git checkout -b feature/xxx` before launching Aider |
| 33 | + |
| 34 | +--- |
| 35 | + |
| 36 | +## Pitfall 2: `/add` Misses a File, AI Hallucinates to Fill the Gap |
| 37 | + |
| 38 | +**Symptom** |
| 39 | +- You ask Aider to change `ServiceA`, it does |
| 40 | +- But ServiceA depends on `UtilB` whose signature actually changed — Aider doesn't know, generates code calling a nonexistent signature |
| 41 | +- Runtime: `TypeError` |
| 42 | + |
| 43 | +**Cause** |
| 44 | +Aider only reads files that are explicitly `/add`-ed. Map mode indexes structure (names + positions) but **not contents**. Dependencies not added → AI guesses from names. |
| 45 | + |
| 46 | +**Recovery** |
| 47 | +``` |
| 48 | +/add src/utils/UtilB.ts |
| 49 | +# Let it re-read with the dependency included |
| 50 | +Re-check ServiceA's use of UtilB; make sure you're using the right signature |
| 51 | +``` |
| 52 | + |
| 53 | +**Prevention** |
| 54 | +Have Aider enumerate dependencies first: |
| 55 | + |
| 56 | +``` |
| 57 | +/ask |
| 58 | +I'm about to refactor ServiceA. List all files it directly depends on, |
| 59 | +and all files that call its public API. Give me /add commands |
| 60 | +so I can add them all at once. |
| 61 | +``` |
| 62 | + |
| 63 | +Then `/add` everything it listed before starting `/code`. |
| 64 | + |
| 65 | +--- |
| 66 | + |
| 67 | +## Pitfall 3: Model Switched, Behavior Collapsed |
| 68 | + |
| 69 | +**Symptom** |
| 70 | +- You used Claude, got used to its rigor |
| 71 | +- Switched to DeepSeek to save money; **same prompts, quality drops a cliff** |
| 72 | +- Complex refactors start producing odd bugs; Architect plans become shallow |
| 73 | + |
| 74 | +**Cause** |
| 75 | +LLMs vary wildly in instruction-following. Same `/architect design a WebSocket notification system`: |
| 76 | +- Claude Sonnet: asks follow-ups, handles error paths |
| 77 | +- DeepSeek: gives one plan, skips edge cases |
| 78 | +- Local 7B: structurally correct but detail-poor |
| 79 | + |
| 80 | +**Recovery** |
| 81 | +- Complex task, model can't keep up: switch back to Claude for that step only, then switch back |
| 82 | +- Configure tiered models: strong for reasoning, weak for commit-messages/simple tasks |
| 83 | + |
| 84 | +**Prevention** |
| 85 | +Tier in `.aider.conf.yml`: |
| 86 | + |
| 87 | +```yaml |
| 88 | +model: claude-3-5-sonnet # Primary |
| 89 | +weak-model: deepseek/deepseek-chat # Weak tasks (commit messages, simple completion) |
| 90 | +editor-model: claude-3-5-haiku # Editor-mode completion |
| 91 | +``` |
| 92 | +
|
| 93 | +Or switch **by task type**: |
| 94 | +
|
| 95 | +| Task | Model | |
| 96 | +|------|-------| |
| 97 | +| `/architect` design | Claude Sonnet/Opus | |
| 98 | +| `/code` implement an approved plan | DeepSeek is fine | |
| 99 | +| `/ask` Q&A | any | |
| 100 | +| Large refactor | Claude Opus | |
| 101 | + |
| 102 | +--- |
| 103 | + |
| 104 | +## Pitfall 4: Lint/Test Auto-Loop Blows Up the Bill |
| 105 | + |
| 106 | +**Symptom** |
| 107 | +- You enabled `auto-lint: true` and `auto-test: true` |
| 108 | +- Aider edits, lint fails, it retries the fix, fails, retries... |
| 109 | +- A single session burns 5× expected tokens |
| 110 | + |
| 111 | +**Cause** |
| 112 | +Aider's auto-lint/test retries "if it fails, let the LLM try again." If the problem isn't code-fixable (environment, dependencies), it'll retry until it hits the retry cap. Each retry costs tokens. |
| 113 | + |
| 114 | +**Recovery** |
| 115 | +``` |
| 116 | +/undo # Roll back this round |
| 117 | +/lint-cmd none # Temporarily disable auto-lint |
| 118 | +# Fix the real problem (environment/config), then re-enable |
| 119 | +``` |
| 120 | +
|
| 121 | +**Prevention** |
| 122 | +- Cap retries: `aider --max-reflections 3` |
| 123 | +- Use auto-fixing linters so the linter resolves what it can before handing to AI: |
| 124 | +
|
| 125 | +```yaml |
| 126 | +lint-cmd: "eslint --fix" # not "eslint" |
| 127 | +``` |
| 128 | + |
| 129 | +- Fail-fast tests: |
| 130 | + |
| 131 | +```yaml |
| 132 | +test-cmd: "pytest -x --maxfail=1" |
| 133 | +``` |
| 134 | +
|
| 135 | +--- |
| 136 | +
|
| 137 | +## Pitfall 5: Stale Map — References Deleted Files |
| 138 | +
|
| 139 | +**Symptom** |
| 140 | +- Project structure changed (directories removed, modules renamed) |
| 141 | +- Aider still "remembers" the old structure, generates imports to nonexistent modules |
| 142 | +- Or `/ls` output doesn't match disk |
| 143 | + |
| 144 | +**Cause** |
| 145 | +Map mode is built **at session start**. Large git-level changes (branch switch, rebase, mass deletions) during a session don't auto-refresh the map. |
| 146 | + |
| 147 | +**Recovery** |
| 148 | +Exit and relaunch Aider — the map rebuilds. |
| 149 | +Or in-session: |
| 150 | +``` |
| 151 | +/reset # Clear session context |
| 152 | +/map-refresh # Re-scan project structure (if your version supports it) |
| 153 | +``` |
| 154 | + |
| 155 | +**Prevention** |
| 156 | +- Restart Aider after branch switches (don't span branches in one session) |
| 157 | +- Restart after mass file changes |
| 158 | +- Long sessions: `/reset` periodically to refresh state |
| 159 | + |
| 160 | +--- |
| 161 | + |
| 162 | +## Pitfall 6: Architect Plan Is Solid, Code Execution Drifts |
| 163 | + |
| 164 | +**Symptom** |
| 165 | +- `/architect` produces a clean plan, you approve it |
| 166 | +- Switch to `/code`, first couple files match — then it drifts |
| 167 | +- Final implementation looks almost nothing like the plan |
| 168 | + |
| 169 | +**Cause** |
| 170 | +Architect and Code modes **share session context**, but the Architect plan is long; as Code mode edits file after file, early planning content gets pushed out of context. |
| 171 | + |
| 172 | +**Recovery** |
| 173 | +``` |
| 174 | +# After each implementation step, checkpoint against the plan |
| 175 | +/ask Compare the current implementation to the Architect plan. |
| 176 | +Where has it drifted? |
| 177 | +``` |
| 178 | +
|
| 179 | +**Prevention** |
| 180 | +- Immediately write the Architect plan to a file: `Save this plan to docs/arch.md. We'll implement from that file.` |
| 181 | +- At implementation time, re-reference: `/add docs/arch.md Implement the next step per this file.` |
| 182 | +- For complex tasks, **one session per sub-module** — avoid long-session drift |
| 183 | +
|
| 184 | +--- |
| 185 | +
|
| 186 | +## Pitfall 7: `--amend` Goes Sideways After Aider Commits |
| 187 | +
|
| 188 | +**Symptom** |
| 189 | +- You ask Aider to adjust something (auto-committed) |
| 190 | +- It makes another commit |
| 191 | +- You want to "fold these together," so you `--amend` |
| 192 | +- But amend sucks in your **previously stashed content**, or Aider's two changes into one — history ends up messier |
| 193 | +
|
| 194 | +**Cause** |
| 195 | +Aider commits "after each change," not atomically per logical unit. Manual amend pulls in all currently-staged content. Aider itself doesn't support fine-grained commit control. |
| 196 | +
|
| 197 | +**Recovery** |
| 198 | +```bash |
| 199 | +git reflog # Find pre-amend state |
| 200 | +git reset --hard HEAD@{N} # Roll back |
| 201 | +# Rewrite history cleanly |
| 202 | +git rebase -i HEAD~5 |
| 203 | +``` |
| 204 | + |
| 205 | +**Prevention** |
| 206 | +- Squash at end of session: |
| 207 | + ```bash |
| 208 | + git reset --soft HEAD~N # N = number of Aider commits |
| 209 | + git commit -m "feat: add notifications" |
| 210 | + ``` |
| 211 | +- Don't `--amend` during an Aider session |
| 212 | +- Tag key checkpoints yourself: `git tag wip-before-aider` — rollback is cheap |
| 213 | + |
| 214 | +--- |
| 215 | + |
| 216 | +## Contribute a Pitfall |
| 217 | + |
| 218 | +Template: see [claude-code.en.md end](./claude-code.en.md#found-a-new-pitfall). |
| 219 | + |
| 220 | +--- |
| 221 | + |
| 222 | +## Related |
| 223 | + |
| 224 | +- [Aider Full Guide](../aider/README.en.md) |
| 225 | +- [common/task-decomposition.en.md](../common/task-decomposition.en.md) — Task decomposition (Aider relies on this heavily) |
| 226 | +- [common/debugging.en.md](../common/debugging.en.md) — Systematic debugging |
0 commit comments