{"course":{"slug":"building-apps-with-ai","title":"Building Apps with AI","url":"https://addaly.com/learn/building-apps-with-ai","level":"beginner","track":"build"},"lesson":{"slug":"when-the-model-breaks-your-app","title":"When the model breaks your app","url":"https://addaly.com/learn/building-apps-with-ai/when-the-model-breaks-your-app","position":28,"of":87,"minutes":8,"answer":"Two failed fixes means stop, revert to a working state, and reproduce the bug before asking again.","keyIdea":"Two failed fixes means stop, revert to a working state, and reproduce the bug before asking again."},"body":{"format":"markdown","text":"## The doom loop\n\nIt goes like this. Something errors. You paste the error. The model changes three files. A different error appears. You paste that. It changes five files. The original feature stops working. You paste more. Two hours later the app does not start, you cannot remember what it looked like when it worked, and the model is now suggesting you reinstall your dependencies.\n\nEveryone building this way hits it. The way out is not a better prompt. It is a procedure.\n\n## Stop after two\n\nHard rule: if two attempts at the same error both fail, stop asking. The third attempt is where damage starts, because the model is now working on a codebase that contains its own failed guesses.\n\nGo back to the last state that worked. Lesson 5 covers how. If you have no save point, this is the moment you learn why you need one.\n\n## Read the error yourself\n\nErrors look like noise. They are not. You need three pieces from them.\n\n```\nTypeError: Cannot read properties of undefined (reading 'name')\n    at BookingCard (/app/components/BookingCard.tsx:23:31)\n    at renderWithHooks (/node_modules/react-dom/cjs/react-dom.js:14985:18)\n    at mountIndeterminateComponent (/node_modules/react-dom/cjs/react-dom.js:17811:13)\n```\n\n**Line one is the what.** Something was undefined and the code asked it for `.name`. Almost certainly a booking that was expected and was not there.\n\n**The first line mentioning your own files is the where.** `BookingCard.tsx`, line 23. The `node_modules` lines below are the library's internals; you can ignore them nearly always.\n\n**What you did just before is the when.** Did it break on page load, or after you clicked something?\n\nWith those three you can write a request worth sending. Without them you are forwarding noise and hoping.\n\n## Reproduce it before you fix it\n\nCan you make it happen on purpose, every time? If yes, you can tell when it is fixed. If no, you cannot, and any fix you accept is a guess that happened to coincide with the bug not appearing.\n\nWrite the steps down in one line: \"Log in, go to /bookings, click any row for a cancelled booking. Blank page.\" That sentence is worth more to the model than the stack trace.\n\n## Change one thing\n\nWhen you do ask for a fix, constrain it:\n\n```\nThis error happens every time I click a cancelled booking:\n[paste the first three lines]\n\nReproduce: log in, /bookings, click a cancelled row.\n\nI already tried adding a null check in BookingRow — no change.\n\nFix only BookingCard.tsx. Do not change the database schema,\ndo not touch the API route, do not refactor anything.\nExplain the cause before you write code.\n```\n\nThe restrictions matter as much as the description. Left unbounded, an agent asked to fix a display bug will sometimes rewrite your data layer because it noticed something it did not like.\n\n\"Explain the cause before you write code\" is the highest-value sentence in that prompt. If the explanation is vague (\"there may be a state issue\") the fix will be vague too, and you should not accept it.\n\n## When the fix works, find out why\n\nSometimes an error disappears and you have no idea what changed. That is not fixed. That is postponed. Ask: \"which line caused the error, and which line prevents it now?\" If the answer is a wrapped `try/catch` that hides the failure, the bug is still there and now it is silent.\n\n## Delete and redo is a legitimate move\n\nAfter several rounds of patching, a feature can end up as sediment: layers of half-applied fixes, dead branches, two functions doing similar things. Repairing that costs more than rebuilding it.\n\nRevert to before the feature existed. Write a better description than the one you used the first time, now that you know what went wrong. Build it again in one clean pass. This often takes fifteen minutes and feels like a failure. It is not. It is the cheapest option on the table.\n\n## The thing that makes all of this possible\n\nEvery instruction in this lesson assumes you can get back to a working version. If you cannot, none of it applies and you are just hoping. That is the next lesson."},"check":{"question":"Three attempts to fix one error have each produced a new, different error, and the app is now worse than when you started. What is the best next move?","options":[{"text":"Paste the entire file and ask for a complete rewrite, so the model has full context.","correct":false,"tempting":"Assumes the failures came from insufficient context, when they came from the model editing a codebase that already contains its own failed guesses."},{"text":"Switch to a more capable model and send it the same error message.","correct":false,"tempting":"Treats model strength as the bottleneck, which ignores that the code being reasoned about is now damaged regardless of who reads it."},{"text":"Return to the last save point where the app worked, then ask again with a narrower request.","correct":true},{"text":"Send the error again along with an instruction to be more careful and not break anything else.","correct":false,"tempting":"Believes the problem is insufficient instruction, when tone and caution language do not undo three layers of accumulated edits."}]},"prev":{"slug":"printing-what-you-cannot-see","title":"Printing what you cannot see","url":"https://addaly.com/learn/building-apps-with-ai/printing-what-you-cannot-see"},"next":{"slug":"anatomy-of-an-error-message","title":"The anatomy of an error message","url":"https://addaly.com/learn/building-apps-with-ai/anatomy-of-an-error-message"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'When the model breaks your app', in Building Apps with AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/building-apps-with-ai/when-the-model-breaks-your-app (Accessed: 31 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"When the model breaks your app","courseTitle":"Building Apps with AI","module":{"index":4,"slug":"when-it-breaks","title":"When it breaks, and getting back"},"answer":null,"keyIdea":"Two failed fixes means stop, revert to a working state, and reproduce the bug before asking again.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"the-doom-loop","runs":[{"text":"The doom loop"}]},{"t":"p","runs":[{"text":"It goes like this. Something errors. You paste the error. The model changes three files. A different error appears. You paste that. It changes five files. The original feature stops working. You paste more. Two hours later the app does not start, you cannot remember what it looked like when it worked, and the model is now suggesting you reinstall your dependencies."}]},{"t":"p","runs":[{"text":"Everyone building this way hits it. The way out is not a better prompt. It is a procedure."}]},{"t":"h2","id":"stop-after-two","runs":[{"text":"Stop after two"}]},{"t":"p","runs":[{"text":"Hard rule: if two attempts at the same error both fail, stop asking. The third attempt is where damage starts, because the model is now working on a codebase that contains its own failed guesses."}]},{"t":"p","runs":[{"text":"Go back to the last state that worked. Lesson 5 covers how. If you have no save point, this is the moment you learn why you need one."}]},{"t":"h2","id":"read-the-error-yourself","runs":[{"text":"Read the error yourself"}]},{"t":"p","runs":[{"text":"Errors look like noise. They are not. You need three pieces from them."}]},{"t":"code","lang":"","label":"Text","text":"TypeError: Cannot read properties of undefined (reading 'name')\n    at BookingCard (/app/components/BookingCard.tsx:23:31)\n    at renderWithHooks (/node_modules/react-dom/cjs/react-dom.js:14985:18)\n    at mountIndeterminateComponent (/node_modules/react-dom/cjs/react-dom.js:17811:13)"},{"t":"p","runs":[{"text":"Line one is the what.","b":true},{"text":" Something was undefined and the code asked it for "},{"text":".name","code":true},{"text":". Almost certainly a booking that was expected and was not there."}]},{"t":"p","runs":[{"text":"The first line mentioning your own files is the where.","b":true},{"text":" "},{"text":"BookingCard.tsx","code":true},{"text":", line 23. The "},{"text":"node_modules","code":true},{"text":" lines below are the library’s internals; you can ignore them nearly always."}]},{"t":"p","runs":[{"text":"What you did just before is the when.","b":true},{"text":" Did it break on page load, or after you clicked something?"}]},{"t":"p","runs":[{"text":"With those three you can write a request worth sending. Without them you are forwarding noise and hoping."}]},{"t":"h2","id":"reproduce-it-before-you-fix-it","runs":[{"text":"Reproduce it before you fix it"}]},{"t":"p","runs":[{"text":"Can you make it happen on purpose, every time? If yes, you can tell when it is fixed. If no, you cannot, and any fix you accept is a guess that happened to coincide with the bug not appearing."}]},{"t":"p","runs":[{"text":"Write the steps down in one line: “Log in, go to /bookings, click any row for a cancelled booking. Blank page.” That sentence is worth more to the model than the stack trace."}]},{"t":"h2","id":"change-one-thing","runs":[{"text":"Change one thing"}]},{"t":"p","runs":[{"text":"When you do ask for a fix, constrain it:"}]},{"t":"code","lang":"","label":"Text","text":"This error happens every time I click a cancelled booking:\n[paste the first three lines]\n\nReproduce: log in, /bookings, click a cancelled row.\n\nI already tried adding a null check in BookingRow — no change.\n\nFix only BookingCard.tsx. Do not change the database schema,\ndo not touch the API route, do not refactor anything.\nExplain the cause before you write code."},{"t":"p","runs":[{"text":"The restrictions matter as much as the description. Left unbounded, an agent asked to fix a display bug will sometimes rewrite your data layer because it noticed something it did not like."}]},{"t":"p","runs":[{"text":"“Explain the cause before you write code” is the highest-value sentence in that prompt. If the explanation is vague (“there may be a state issue”) the fix will be vague too, and you should not accept it."}]},{"t":"h2","id":"when-the-fix-works-find-out-why","runs":[{"text":"When the fix works, find out why"}]},{"t":"p","runs":[{"text":"Sometimes an error disappears and you have no idea what changed. That is not fixed. That is postponed. Ask: “which line caused the error, and which line prevents it now?” If the answer is a wrapped "},{"text":"try/catch","code":true},{"text":" that hides the failure, the bug is still there and now it is silent."}]},{"t":"h2","id":"delete-and-redo-is-a-legitimate-move","runs":[{"text":"Delete and redo is a legitimate move"}]},{"t":"p","runs":[{"text":"After several rounds of patching, a feature can end up as sediment: layers of half-applied fixes, dead branches, two functions doing similar things. Repairing that costs more than rebuilding it."}]},{"t":"p","runs":[{"text":"Revert to before the feature existed. Write a better description than the one you used the first time, now that you know what went wrong. Build it again in one clean pass. This often takes fifteen minutes and feels like a failure. It is not. It is the cheapest option on the table."}]},{"t":"h2","id":"the-thing-that-makes-all-of-this-possible","runs":[{"text":"The thing that makes all of this possible"}]},{"t":"p","runs":[{"text":"Every instruction in this lesson assumes you can get back to a working version. If you cannot, none of it applies and you are just hoping. That is the next lesson."}]}],"check":{"question":[{"text":"Three attempts to fix one error have each produced a new, different error, and the app is now worse than when you started. What is the best next move?"}],"options":[{"text":[{"text":"Paste the entire file and ask for a complete rewrite, so the model has full context."}],"correct":false,"tempting":[{"text":"Assumes the failures came from insufficient context, when they came from the model editing a codebase that already contains its own failed guesses."}]},{"text":[{"text":"Switch to a more capable model and send it the same error message."}],"correct":false,"tempting":[{"text":"Treats model strength as the bottleneck, which ignores that the code being reasoned about is now damaged regardless of who reads it."}]},{"text":[{"text":"Return to the last save point where the app worked, then ask again with a narrower request."}],"correct":true,"tempting":null},{"text":[{"text":"Send the error again along with an instruction to be more careful and not break anything else."}],"correct":false,"tempting":[{"text":"Believes the problem is insufficient instruction, when tone and caution language do not undo three layers of accumulated edits."}]}],"order":[3,2,0,1],"why":null},"prev":{"slug":"printing-what-you-cannot-see","title":"Printing what you cannot see","minutes":8},"next":{"slug":"anatomy-of-an-error-message","title":"The anatomy of an error message","minutes":8}}}