How to Resolve Error "CS0158: The label 'label' shadows another label by the same name in a contained scope" in C#
The Compiler Error CS0158 is a naming conflict error related to Control Flow and Scope. The message reads: "The label 'LabelName' shadows another label by the same name in a contained scope".
In C#, standard variables have block scope (variables inside an if block are distinct from outside, though shadowing is generally disallowed in C# unlike C++). Labels (used with goto) generally have Method Scope, meaning a label defined anywhere in a method is visible to the entire method.
However, if you define a label inside a nested block (like an if statement or a generic scope { }) that has the same name as a label in the outer scope, the inner label "shadows" (hides) the outer one. This makes the outer label inaccessible from within that block, creating ambiguity. The compiler flags this as an error to prevent logical jumps to the wrong location.
Understanding Label Shadowing
When you write goto MyLabel;, the compiler looks for MyLabel:.
If you have the following structure:
- Outer Scope: Defines
MyLabel:. - Inner Scope: Defines
MyLabel:.
Inside the inner scope, goto MyLabel; would technically refer to the inner label. The outer label becomes "shadowed" (invisible). C# considers this dangerous because it is easy to assume a goto is jumping to a main error handler, when in fact it is trapped inside a small inner loop.
Scenario: Nested Block Label Conflict
This error commonly occurs when copy-pasting code blocks that contain labels into a method that already uses that label name.
Example of error:
public class DataProcessor
{
public void Run()
{
// Outer scope label
Finished:
System.Console.WriteLine("Outer Process Finished.");
if (true)
{
// ... some logic ...
// ⛔️ Error CS0158: The label 'Finished' shadows another label
// by the same name in a contained scope.
// This definition makes the outer 'Finished' inaccessible inside this 'if' block.
Finished:
System.Console.WriteLine("Inner Process Finished.");
}
}
}
Solution 1: Rename the Inner Label
The most direct fix is to ensure every label in your method has a unique, descriptive name. This resolves the ambiguity and allows you to target specific jump points.
public class DataProcessor
{
public void Run()
{
// Label 1
OuterFinished:
System.Console.WriteLine("Outer Process Finished.");
if (true)
{
// ... some logic ...
// ✅ Correct: Unique name avoids shadowing
InnerFinished:
System.Console.WriteLine("Inner Process Finished.");
// You can now jump to either specific location
// goto OuterFinished;
// goto InnerFinished;
}
}
}
Solution 2: Refactor to Remove goto
If you are encountering CS0158, it is often a symptom of "Spaghetti Code"—logic that relies too heavily on unstructured jumps. In modern C#, goto is rarely necessary. You can usually replace the logic with functions, break, return, or continue.
Refactoring Example: instead of jumping to labels to print "Finished", move the inner logic to a separate method.
public class DataProcessor
{
public void Run()
{
// Logic for the outer scope
System.Console.WriteLine("Outer Process Finished.");
if (true)
{
// ✅ Correct: Encapsulate the inner logic in a method.
// No labels are needed, avoiding conflict entirely.
RunInnerProcess();
}
}
private void RunInnerProcess()
{
// ... some logic ...
System.Console.WriteLine("Inner Process Finished.");
}
}
Usage Advice: While goto is valid C#, limiting its use makes code easier to read, test, and debug. Prioritize structured control flow (if/else, loops, methods) over labels.
Conclusion
CS0158 protects you from ambiguous control flow targets.
- Identify Scopes: Look for curly braces
{ }creating nested blocks. - Check Names: Find the label name that appears in both the outer method and the inner block.
- Rename: Give the labels distinct names (e.g.,
RetryConnectvsRetryLogin) to fix the shadowing.