An error message disappears. The result is still wrong. That is an easy mistake to make when you ask an AI assistant to “fix this code” and accept the first version that runs.
A useful debugging conversation starts with something smaller: the input, the failure and the result you actually need. Here is a short Python example where that distinction matters.
Start with a failure you can reproduce#
Suppose an imported order line has a unit price and a quantity. Prices in this example are whole cents, and a price is required.
def line_total(item):
return item["price_cents"] * item["quantity"]
item = {"unit_price_cents": 1200, "quantity": 2}
print(line_total(item))The expected total is 2400 cents. Instead, the code raises KeyError: 'price_cents'.
There is already enough information to investigate: the function reads price_cents, while the input contains unit_price_cents. Python's dictionary documentation explains that accessing a missing key this way raises KeyError.
You do not need to paste the whole application into a chat. First isolate the function and replace real customer information, tokens and private endpoints with made-up values. Keep the structure that triggers the failure.
Ask for an explanation before a rewrite#
“Fix this” leaves important decisions open. Does a missing price mean zero? Is the function wrong, or did the importer change its output?
Give the assistant that context explicitly:
This function raises KeyError: 'price_cents'. The importer intentionally supplies unit_price_cents, and the expected total for this input is 2400. A missing unit price must remain an error, not become zero. Explain the mismatch, suggest the smallest change and show how to check it. Do not rename the importer's fields or add dependencies.
Paste the small example underneath. This does not guarantee a correct answer. It does give you a specific proposal to review rather than a new implementation with different assumptions.
If the answer says the importer is broken, ask what evidence supports that. In this example, the stated contract says otherwise. An assistant should not quietly replace that contract with a guess.
Check the result, not just the exception#
Consider this possible change:
return item.get("price_cents", 0) * item["quantity"]It stops the exception for the supplied input. It also returns zero, because price_cents is still absent. Python's dict.get returns the fallback when a key is missing; that behavior is useful only when the fallback means what your program needs it to mean.
For the contract above, the small correction is:
def line_total(item):
return item["unit_price_cents"] * item["quantity"]Now the example returns 2400. More importantly, the code reads the field the importer actually provides. This example addresses the field-name mismatch; a real application would also need to decide which input types and values are allowed.
Keep a check that would catch the original mistake#
Before accepting a change, run it against an expected result you chose independently of the assistant's answer:
assert line_total({"unit_price_cents": 1200, "quantity": 2}) == 2400
assert line_total({"unit_price_cents": 1200, "quantity": 0}) == 0
try:
line_total({"quantity": 2})
except KeyError:
pass
else:
raise AssertionError("A missing price must not become zero")The first check catches the field mismatch. The second covers a zero quantity. The final check protects the decision that a missing price is an error. If your application has a test suite, put these cases into its normal test framework rather than leaving them as a one-off experiment.
AI can suggest additional cases, but check their expected results yourself. A test that repeats the same mistaken assumption as the proposed fix will happily approve it.
Add context when the evidence calls for it#
Some bugs will not survive a five-line reduction. If the small example works but the application fails, the next useful input might be the caller, a sanitized failing record or the relevant library version. Add the part that explains that difference, rather than sending unrelated files.
Ask the assistant to separate what the example proves from what it is assuming. Then inspect the proposed change in a diff. A new dependency, a broad exception handler or a disabled check deserves an explanation when the original problem was one field name.
GitHub's guidance for Copilot Chat also calls for reviewing generated output and testing code. A convincing explanation is a starting point; the input, expected result and checks decide whether the fix belongs in your project.
For the next bug, write those three things down before opening the chat. They will make the answer easier to judge, even if you end up finding the fix yourself.



