Lessons
1 · Understanding Modern AI
2 · Talking to AI Effectively
3 · AI for Learning
4 · AI for Work and Productivity
5 · AI for Developers
- 17AI Coding Assistants: Modes, Strengths and Your Responsibility
- 18Use AI to Understand Code, Codebases, APIs and Documentation
- 19How to Use AI to Debug Code Safely
- 20Testing, Reviewing and Refactoring AI-Generated Code
- 21Security and Licensing Risks of AI-Generated Code
- 22Vibe Coding vs Responsible AI-Assisted Building
6 · AI for Career Growth
7 · Research, Verification and Responsible AI
8 · Automation and AI Agents
Lesson 19 · AI for Developers
How to Use AI to Debug Code Safely
Pasting an error into an assistant can solve a bug in a minute, or produce a patch that hides it. This article gives a safe debugging workflow: reproduce, share safely, ask for hypotheses, test them, review the fix, add a regression test, with a worked example and a list of dangerous 'fixes'.
For
Students and developers who use AI assistants to find and fix bugs and want to avoid wasted time, symptom-hiding patches and accidental data exposure.
Level
Before you start
Read AI Coding Assistants: Modes, Strengths and Your Responsibility (article 17). Basic Python reading ability for the example.
On this page
Key takeaways
- Treat the assistant as a source of hypotheses, not a patch dispenser. Reproduce the bug first, then ask for ranked causes and ways to test each.
- Share the smallest useful piece of code and error, and remove secrets, tokens, customer data and proprietary details before pasting.
- Review every proposed fix for whether it addresses the cause or only hides the symptom. Watch for blanket exception handlers, disabled checks and deleted tests.
- Add a regression test that fails before the fix and passes after it. Make sure you can explain why the bug happened.
- Run commands an assistant suggests only when you understand them, ideally on a branch or in a sandbox, never destructive ones on data you cannot restore.
A bug report arrives at 4 p.m. on Friday. You paste the stack trace into an assistant and, within seconds, get a patch. It makes the error go away. You ship it. On Monday you discover that the error went away because the patch quietly swallowed it, and now the wrong data is being written without any warning.
Debugging is where AI help is most tempting and where the gap between "the error disappeared" and "the bug is fixed" is widest. This article shows how to get the speed without the trap.
What you will learn
#- A safe, step-by-step debugging workflow with an assistant.
- What to share and what never to paste.
- A worked example in which the obvious fix is wrong.
- Common "fixes" that hide bugs.
- How to treat commands that an assistant suggests you run.
The idea in plain words
#Debugging is the scientific method applied to code: observe what happens, form a hypothesis about why, test it, and repeat. An assistant is very good at generating hypotheses, because it has seen countless similar bugs. It is much less reliable at knowing which one is true for your program, because it cannot run your code, see your data or know your environment (unless it is an agent that can, in which case the same caution applies to its actions).
So split the work: it proposes, you test. For a foundation in systematic debugging without AI, see How to Debug Any Bug: A Calm, Repeatable Process.
The workflow
#- Reproduce. Make the bug happen reliably. If you cannot reproduce it, no assistant can help you fix it.
- Shrink it. Cut away everything that is not needed to trigger the bug, until you have the smallest example. This often reveals the cause by itself.
- Write down expected versus actual. "I expected 35. I got 25."
- Prepare a safe, minimal share (see below).
- Ask for hypotheses, ranked, with a test for each, not a patch.
- Test the hypotheses yourself: a log line, a debugger, a unit test, a print.
- Ask for the smallest fix for the confirmed cause.
- Review the diff (see the symptom-hiding list).
- Add a regression test that fails before the fix and passes after.
- Explain the bug in a sentence. If you cannot, you have not finished.
A prompt for step 5:
I have a bug. Expected: average_of_last([10, 20, 30, 40], 0) should not returna number, since there is nothing to average. Actual: it returns 25.0.Python 3.11. Code: [paste function].Do not give me a fix yet. List the three most likely causes in order oflikelihood, and for each give one quick way I can test whether it is the cause.Asking for causes and tests keeps you in control, and it works well because the assistant's strength (breadth of experience) is used while its weakness (not seeing your runtime) is routed around.
A worked example
#The function. It should return the average of the last n values of a list.
# File: last_n_average.pydef average_of_last(values, n): """Return the average of the last n values (buggy first version).""" window = values[-n:] return sum(window) / len(window)def average_of_last_fixed(values, n): """Return the average of the last n values, or None when there is nothing to average.""" if n <= 0 or not values: return None window = values[-n:] return sum(window) / len(window)scores = [10, 20, 30, 40]print("n=2 buggy:", average_of_last(scores, 2))print("n=0 buggy:", average_of_last(scores, 0))print("n=2 fixed:", average_of_last_fixed(scores, 2))print("n=0 fixed:", average_of_last_fixed(scores, 0))print("empty fixed:", average_of_last_fixed([], 3))n=2 buggy: 35.0n=0 buggy: 25.0n=2 fixed: 35.0n=0 fixed: Noneempty fixed: NoneThe symptom. average_of_last(scores, 0) returns 25.0, which is the average of all the values. A user reported "my chart shows an average when I selected zero days".
What a hurried assistant might suggest (illustrative): "Wrap the function in a try/except and return 0 on error", or "add if n == 0: return 0."
Why those are wrong. Neither explains the cause. The real cause: in Python, values[-0:] is the same as values[0:], because -0 equals 0, so the slice starts at the beginning and returns the whole list. The code never failed, so a try/except does nothing. And return 0 invents a number: an average of nothing is not zero.
Hypothesis testing. Quick checks confirm it: print values[-0:] and values[-2:] and compare. Cause confirmed.
The fix and its design decision. The fixed function returns None for "nothing to average", so callers can tell it from a real average of 0. Whether to return None, raise an error or return 0 is a design decision that depends on the callers, not something the assistant can decide for you. In the output above, the fixed version gives 35.0 for n=2 as before, and None for both n=0 and an empty list.
Regression test. Add tests such as: n=2 gives 35.0, n=0 gives None, an empty list gives None, n larger than the list length uses all values. Verify that the n=0 test fails on the old code and passes on the new.
Understanding. One sentence: "A negative-zero slice index starts at the beginning, so n=0 returned the whole list." You could now spot this class of bug elsewhere.
What to share, and what never to paste
#Debugging prompts tend to contain the most sensitive material, because errors reveal internals.
Never paste, into any tool not approved for it:
- Passwords, API keys, tokens, private keys, connection strings,
.envfiles. - Customer data, personal data, production database contents.
- Proprietary source code, if your employer does not allow it.
- Stack traces and logs that include internal hostnames, user emails or file paths you should not expose.
What to do instead:
- Redact. Replace secrets and identifiers with placeholders (
<API_KEY>,user@example.com). - Minimise. Share the smallest function and the error, not the whole repository.
- Use a made-up reproduction. Often you can recreate the bug with fake data.
- If you ever paste a real secret by accident, treat it as exposed: rotate it (create a new one and disable the old) and tell your security contact if you have one.
Privacy and Security covers this in more detail.
"Fixes" that hide bugs
#Review every proposed change against this list:
Pattern | Why it is dangerous |
|---|---|
Wrapping code in a broad | The bug continues silently, and your data may be wrong |
Returning a default value (0, empty string) when something fails | Invents data and hides failure |
Adding | Masks a race condition or a slow dependency |
Disabling validation, type checks or certificate verification | Removes a safeguard to make a symptom go away |
Special-casing the failing input | Fixes your test, not the logic |
Deleting or loosening the failing test | Fixes the report, not the program |
Pinning, downgrading or "force" flags without understanding | Can hide an incompatibility or reintroduce a vulnerability |
A large rewrite for a small bug | Increases the area you must review |
Ask yourself after reading the diff: "Does this change the cause, or only what I see?"
Commands the assistant tells you to run
#Assistants will sometimes tell you to run shell commands, change permissions or reinstall packages. Before running anything:
- Understand it. Ask for an explanation of each part, and check it in the official documentation of the tool.
- Be wary of destructive or broad commands: deleting files, force-pushing, changing permissions recursively, running scripts downloaded and piped straight into a shell, disabling security features.
- Work on a branch or copy, with version control and backups, so you can undo.
- Prefer the smallest scope (one folder, one file, a dry run if the tool offers it).
If you use an agent mode that runs commands for you, set the permissions narrowly, require approval for risky actions and review what it ran. Module 8 returns to this.
When the assistant goes in circles
#If you have tried three fixes and the problem persists:
- Stop and restate the problem in two sentences with expected versus actual behaviour.
- Start a new conversation with the cleaned-up minimal reproduction, because the old thread may be cluttered by failed ideas.
- Ask it to explain the code before fixing it. If the explanation is wrong, you have found the misunderstanding.
- Question your own assumptions. Is the input what you think? Is it the code you think is running?
- Take a break or ask a colleague. A person who sees the problem fresh often finds it quickly.
Bugs that need measurement
#Concurrency problems, performance regressions and memory leaks are hard to guess at. Do not accept a confident diagnosis. Collect evidence with profilers, logs, traces and benchmarks, and give those results to the assistant.
Common mistakes
#- Pasting the error and applying the first patch.
- Skipping the reproduction and then not knowing if the fix worked.
- Pasting secrets or proprietary code.
- Accepting a fix you cannot explain.
- Not adding a regression test.
- Letting the assistant widen the change to "clean up" unrelated code.
- Running unfamiliar commands on a machine or data you cannot restore.
Exercises
#Exercise 1
Cause or symptom?
#An assistant suggests wrapping a database call in try: ... except Exception: pass because the call sometimes raises a timeout. Explain what this does to the bug and propose two better follow-up questions.
Exercise 2: Write the hypothesis prompt
#You have a function parse_price("Rs 1,200") that returns 1 instead of 1200. Write a debugging prompt that asks for ranked hypotheses and tests, without asking for a fix.
Exercise 3: Regression tests
#For average_of_last_fixed, list five test cases (inputs and expected outputs) including edge cases, and say which should fail on the buggy version.
Exercise 4: Sanitise before sharing
#Rewrite this stack-trace line so that it is safe to paste into a public assistant: File "/home/rahul/acme-billing/payments.py", line 88, in charge: requests.post("https://api.acme-internal.example/v2/charge?key=sk_live_EXAMPLE", json=card).
Show solutionHide solution
It does not fix the timeout. It hides it: the failure still happens, but nothing is reported, so the program carries on as if the call had succeeded. Data may not be saved, a payment may not be recorded, and no one will know until the consequences appear.
Better follow-up questions: "What are the possible reasons for a timeout in this call (slow query, network, lock contention, connection pool exhaustion), and how can I test each?" and "If a timeout is expected sometimes, how should my code handle it deliberately: retry with limits, log it, return a clear error to the caller?" The aim is to find the cause and then choose a deliberate response.
Exercise 2
Show solutionHide solution
Bug: parse_price("Rs 1,200") returns 1, but I expect 1200. Python 3.11. Code:[paste the function]. Other inputs: "Rs 500" returns 500 (correct), "1200" returns1200 (correct).Do not give me a fix. List the three most likely causes, ordered by likelihoodgiven these inputs, and for each give one quick test (a print statement or a smallcall) that would confirm or rule it out.Including the other inputs that behave correctly is valuable evidence. It suggests that the comma is involved, which narrows the hypotheses sharply.
Exercise 3
Show solutionHide solution
For average_of_last_fixed:
Input | Expected | Fails on buggy version? |
|---|---|---|
| 35.0 | No |
| None | Yes (returns 25.0) |
| None | Yes (raises an error, because it divides by zero) |
| 15.0 (uses all values) | No |
| 20.0 | No |
On the buggy version, the empty list case actually raises ZeroDivisionError, because the window is empty. That is a second bug the original report did not mention, found because you wrote the edge cases.
Exercise 4
Show solutionHide solution
File "/path/to/project/payments.py", line 88, in charge:requests.post("https://<internal-api-host>/v2/charge?key=<API_KEY>", json=card)Also replace card with a description (json=<example card dict>) if the real value contains payment data. Removed: the username in the path, the internal hostname and the live secret key. If the real key was ever pasted somewhere it should not be, rotate it. A key beginning sk_live suggests a live payment key, which is highly sensitive.
Where to go next
#- Next: Testing, Reviewing and Refactoring AI-Generated Code shows how to test code you did not write.
- For the security side of fixes, see Security and Licensing Risks of AI-Generated Code.
- For what to paste and what not to, see Privacy and Security: What Not to Paste, Connected Tools and Prompt Injection.
- Technology
- AI
- #AI
- #AI coding
- #debugging
- #developers
- #generative AI
- #productivity
- #prompt engineering
- #responsible AI
- #software security
- #testing
Connected lessons
References
Linked from 4 guides
Other pages in the library that point here.
Keep reading
More in Technology →Guide · Technology
Writing Better AI Prompts: A Practical Guide
Guide · Technology
Using AI Tools at Work Without Getting Into Trouble
Guide · Career
A LinkedIn Profile That Gets Recruiter Messages

