What AI Assistants Don't Know About Your .NET Stack (And Will Happily Reproduce)
I've been doing .NET/WPF/SQL Server development for years. A few months ago I started experimenting with AI-assisted development — Claude Code, Cursor, that kind of thing. Not a full switch, just plugging them into my workflow and seeing where they helped and where they got me into trouble.
Here's what I didn't expect: the AI assistants reproduce the exact same silent bugs that junior devs write. Not because they're dumb — they're genuinely impressive — but because they don't know your stack's quirks unless you tell them explicitly. They generate plausible, compilable, sometimes even elegant code that contains time-bombs.
So I started documenting these. After a few months I had about 70 of them, which I've packaged into Claude Code and Cursor config files I use on every project. Here are seven of the nastiest ones.
1. ConfigureAwait(false) in a ViewModel silently kills your bindings
You know the rule: use ConfigureAwait(false) in library/service code. AI assistants know this rule too — so they apply it everywhere, including ViewModels.
The problem: if your ViewModel does await SomeService().ConfigureAwait(false), the continuation runs on a thread pool thread. Setting an ObservableCollection from there throws NotSupportedException. WPF swallows it internally. Your data never appears. No exception, no log, nothing in the output window.
Fix: Services → ConfigureAwait(false), fine. ViewModels that set bound properties → never. This is one of those rules that needs to be in your AI's context, because it will confidently do the wrong thing every time.
2. EF Core migration without .Designer.cs — MigrateAsync returns success and does nothing
Missing the companion .Designer.cs file for a migration? MigrateAsync reports success. No exception. Schema is never updated. You find out in prod when your app crashes on a missing column.
The AI generates migration classes fine. It doesn't always remind you that the designer file needs to exist too, and won't warn you when it's absent. MigrateAsync treats it as "nothing to do."
Fix: Always generate both files. Always check both exist before shipping. I added a startup assertion for this.
3. Multi-user + SqlException 2714 = all pending migrations silently marked as applied
This one burned us in production.
User 1 runs the app, migrations apply fine. User 2 starts the app a few seconds later. They hit error 2714 ("object already exists") on a CREATE TABLE that User 1 already created. Your exception handler catches it, figures the table exists, marks the migration as applied. Fine so far.
Except ALTER TABLE migrations after that one never run. The migration runner doesn't retry them — it assumes they're done because the batch was "handled." Missing columns. Every subsequent user is broken in ways that are very hard to diagnose.
Fix: Pre-migration safety SQL that checks all expected columns actually exist before calling MigrateAsync. Don't trust the migration history table alone in multi-user scenarios.
4. _ = SomeAsync() swallows every exception
Fire-and-forget looks clean. The AI loves it — it's concise, it compiles, it runs.
Every exception thrown inside disappears. No log, no crash, no trace in any debugger. You find out weeks later when data is missing or an operation silently never completed. I've seen this pattern generated automatically for background cache refreshes, telemetry, cleanup jobs — exactly the places where you need to know when things break.
Fix: Implement a SafeFireAndForget extension that wraps the task, adds a continuation, and logs exceptions. Or use Task.Run with an explicit try/catch. Either way, never let the discard operator be your error handler.
5. ComboBox.SelectedItem — reference equality, not value equality
Your binding is correct. The SelectedItem is set in code. Nothing is selected in the UI.
WPF compares object references, not values. If you load items from a DB into ItemsSource, then separately reconstruct a "matching" object and assign it to SelectedItem, WPF doesn't find a match. The objects are equal by value, but not by reference.
The AI will generate this pattern naturally — it's what you'd write if you didn't know WPF internals.
Fix: After loading your collection, find the target item within ItemsSource by ID and assign that exact reference. Never assign a reconstructed object.
SelectedItem = Items.FirstOrDefault(x => x.Id == loadedId);
Simple fix, maddening to debug if you don't know why.
6. @@IDENTITY returns the trigger's insert, not yours
Classic SQL Server trap that predates AI assistants by decades — but they reproduce it faithfully.
Any trigger that inserts into another table resets @@IDENTITY to that table's identity value. You get back the wrong ID and silently associate records to the wrong parent. This affects roughly half the legacy stored procedures I've worked with.
Fix: Always use SCOPE_IDENTITY() or the OUTPUT clause in new code. Always. The AI doesn't know about your triggers unless you tell it.
-- Wrong
SELECT @@IDENTITY
-- Right
SELECT SCOPE_IDENTITY()
7. AI agent re-spawns cost 20–40K tokens each
This one's specific to Claude Code with agent teams, but if you're going in that direction, it matters.
Every time you spawn a new Agent() instead of sending a message to an existing one, you burn 20–40K tokens for re-contextualization. That agent needs to re-read the codebase, the instructions, the state. Four unnecessary re-spawns in a session can cost you 160K tokens — before you've written a line.
I hit this hard when I started automating multi-step workflows. The pattern that works: TeamCreate at the start of a sprint, then SendMessage to assign tasks to existing agents. Never re-spawn what you can message.
The pattern behind all of these
None of these are obscure. They're well-documented if you know to look. The issue is that AI assistants generate code from patterns, and these patterns look right — they compile, they follow conventions, they pass code review if your reviewer doesn't know the specific trap.
The fix isn't to distrust AI assistants. It's to make their context explicit. When I started encoding these gotchas into my Claude Code and Cursor configs — as named rules the assistant loads before generating anything — the failure rate dropped significantly. The assistant doesn't need to rediscover that @@IDENTITY is unreliable if you've told it once, globally.
I've got about 70 of these accumulated now, covering async patterns, WPF bindings, SQL Server edge cases, EF Core pitfalls, and agent orchestration. Packaged as reusable config files that I drop into any project.
What are yours? Drop them in the comments — I'm particularly curious about anything SQL Server or WPF-specific that's bitten you with AI-generated code. The more we document these, the better our configs get.
Top comments (0)