fix-csharp-issue
Debug and explain how to fix C# and .NET errors step by step in a way that teaches as it fixes. Use this skill whenever a user shares a C# compiler error, .NET runtime exception, or build failure — re
SKILL.mdskills/fix-csharp-issue/SKILL.md
GitHubFix C# / .NET Errors
This skill guides clear, educational debugging of C# and .NET errors. The goal is to fix the issue and help the user understand what went wrong — especially the underlying language or framework concept — so they can recognise it next time.
What the user provides
- The error message (ideally the full
dotnet buildoutput or IDE tooltip, including the error code likeCS0103) - The file and/or location where the error appears (e.g. "line 42 in
OrderService.cs") - The relevant code — either pasted inline or available in the workspace
If code is missing from the conversation, check the workspace before asking the user to paste it.
Response structure
Always follow this exact structure. Keep each step brief but clear — one to three sentences per step. The user should learn from the explanation, not just copy-paste the fix.
Step 1 — Identify the error type
Name the error code and category (e.g. CS0103 — Name does not exist in current context) and explain in one sentence what that class of error means in C#.
Step 2 — Pinpoint the cause
Point to the specific expression or declaration that triggered it. Explain why it fails — what the compiler expected or what the runtime encountered versus what it received.
Step 3 — Show the fix
Present the corrected code in a code block. Show the relevant lines with enough surrounding context to locate them. Where multiple valid fixes exist, show the most idiomatic one first and briefly mention alternatives.
Step 4 — Explain why the fix works
In one to two sentences, explain the mechanism: what does the corrected code do differently, and why does it satisfy the compiler or runtime?
Summary
End with a short bullet-point summary (no tables) covering:
- What the root cause was
- What the fix does
- Any general C# / .NET principle worth remembering (e.g. "use
ArgumentNullException.ThrowIfNullat method entry", "don't use sync-over-async", "nullable reference types require explicit null checks")
Tone and style guidelines
- Teach the language, don't just patch. Errors often reflect a misunderstanding of the type system, async model, or framework contract. Surface that clearly.
- Be concise. Avoid lengthy preambles. Get to the diagnosis quickly.
- Use plain language. If you use a C#-specific term (e.g. "value type", "boxing", "captured variable", "discriminated union via pattern matching"), define it briefly inline.
- No tables in the summary. Use bullet points only.
- Match the user's level. Beginners need the concept explained; experienced .NET developers want the precise reasoning.
- One fix at a time. If there are multiple errors, address the most fundamental one first — fixing it often resolves the others. Mention remaining issues at the end.
- Don't suppress warnings blindly. Avoid
#pragma warning disableor!null-forgiving operators as quick fixes; prefer proper null checks, guard clauses, or accurate type annotations. - Use context7 to follow modern documentation guidelines.
Common C# / .NET error patterns — quick reference
Compiler errors (CS codes)
- CS0103 — Name does not exist in current context: Variable, type, or method is out of scope, not imported, or misspelled. Check
usingdirectives and namespace declarations. - CS0246 — Type or namespace not found: Missing
using, missing NuGet package, or a typo in the type name. Check project references and installed packages. - CS0029 — Cannot implicitly convert type: Assigning an incompatible type without an explicit cast. Add a cast, use
.ToString(), or align the types. - CS0161 — Not all code paths return a value: A non-void method has a branch that falls through without a
return. Add the missing return or throw. - CS1998 — Async method lacks
await: A method is markedasyncbut never awaits anything — it runs synchronously. Either addawaitor removeasync/Task. - CS4014 — Call not awaited: An async call result is discarded without
await. This silently swallows exceptions. Addawaitor explicitly assign to_ =if fire-and-forget is intentional. - CS8600 / CS8602 / CS8604 — Nullable reference warnings: Assigning
nullto a non-nullable reference, dereferencing a possibly-null value, or passing a nullable to a non-nullable parameter. Add null checks, use?., or annotate with?. - CS0168 / CS0169 — Unused variable / field: Declared but never used. Either use it, prefix a discard with
_, or remove it.
Runtime exceptions
- NullReferenceException: Dereferencing an object that is
null. Use null-conditional operators (?.),ArgumentNullException.ThrowIfNull, or guard clauses at method entry. - InvalidCastException: Unsafe cast between incompatible types. Use
is/aswith a null/pattern check rather than direct(T)casts. - InvalidOperationException: Calling a method on an object in an invalid state (e.g. enumerating a modified collection, using a disposed resource). Check preconditions before calling.
- StackOverflowException: Infinite recursion without a base case, or accidental infinite property getter. Trace the call chain and add a termination condition.
- TaskCanceledException / OperationCanceledException: A
CancellationTokenwas signalled. Handle gracefully at call sites that may cancel; don't swallow it silently. - DbUpdateConcurrencyException (EF Core): Optimistic concurrency conflict. Implement a retry or last-write-wins strategy; never silently discard.
- ObjectDisposedException: Using a resource after
Dispose()has been called. Ensureusingscopes are correct and services aren't stored past their lifetime.
Build / project issues
- MSBuild target framework mismatch: Project references a library targeting a newer framework. Align
<TargetFramework>values or use multi-targeting. - Duplicate assembly attribute: Two files declare
[assembly: ...]for the same attribute. Remove one, or add<GenerateAssemblyInfo>false</GenerateAssemblyInfo>if auto-generated. - Ambiguous reference: Two
usingdirectives bring in the same type name. Use a fully-qualified name or ausing Alias = Full.Namespace.Typealias.
C# / .NET debugging tips
Read the full error output. dotnet build prints the innermost error last in the chain. Read all lines — secondary messages often contain the exact property or type that mismatched.
Nullable annotations. With <Nullable>enable</Nullable>, the compiler tracks nullability flow. CS8602 on a dereference means the compiler can't prove the value is non-null at that point — add a null check rather than a ! suppressor unless you have a genuine guarantee.
Async pitfalls. Never use .Result or .Wait() on a Task in ASP.NET Core — it causes deadlocks. Always await. If a method can't be async, restructure instead of using sync-over-async escape hatches.
LINQ errors. "Sequence contains no elements" means .First() / .Single() was called on an empty sequence — use .FirstOrDefault() and check for null. "LINQ to Entities does not support..." means a client-side method was used inside an EF Core query — move it to a separate AsEnumerable() step.
Pattern matching over casting. Prefer if (obj is MyType t) { ... } over (MyType)obj — it combines the type check and cast safely and is the idiomatic .NET approach.
Handling incomplete information
If the user gives an error but no code:
- Check the workspace for relevant
.cs/.csprojfiles before asking. - If no code is found, ask for the minimal snippet that reproduces the error — ideally including relevant type definitions or interfaces.
If the error originates inside a NuGet package or generated code, focus on the call site in user-owned code — that's almost always where the real mistake is.
If the error is environment-related (wrong SDK version, missing package, path issue), state so clearly and provide the exact command to fix it (e.g. dotnet add package Foo or dotnet tool install --global dotnet-ef).