The Compiler Error CS0163 is a control flow safety error. The message reads: "Control cannot fall through from one case label ('case X:') to another".
In languages like C or C++, if you omit a break statement at the end of a case block, the program automatically executes the code in the next case block. This behavior is called Fall-Through. C# considers implicit fall-through to be a common source of bugs (executing code unintentionally). Therefore, C# forbids falling through from one non-empty case to another. Every case that contains statements must explicitly end with a jump statement.
This guide explains how to properly terminate case blocks and how to achieve fall-through behavior explicitly if needed.
Understanding the "No Fall-Through" Rule
If a case block contains any instructions (even just a variable declaration or a console print), it is considered "non-empty". A non-empty case must end with one of the following keywords:
break(Exits the switch)return(Exits the method)throw(Exits via exception)goto case <value>(Jumps to another case)goto default(Jumps to default)
If the compiler detects a path where execution reaches the end of the case block and tries to "fall" into the next one, it raises CS0163.
Scenario 1: The Forgotten Break (Common Mistake)
This is the most frequent cause. A developer writes logic for a case but simply forgets to type break; at the end.
Example of error
public void ProcessLevel(int level)
{
switch (level)
{
case 1:
Console.WriteLine("Easy Mode");
// ⛔️ Error CS0163: Control cannot fall through from one case label ('case 1:') to another.
// Execution hits this line and tries to fall into 'case 2', which is forbidden.
case 2:
Console.WriteLine("Medium Mode");
break;
}
}Solution: Add Break
Simply add the break; statement.
public void ProcessLevel(int level)
{
switch (level)
{
case 1:
Console.WriteLine("Easy Mode");
break; // ✅ Correct: Safely exits the switch
case 2:
Console.WriteLine("Medium Mode");
break;
}
}Scenario 2: Incomplete Conditional Paths
If you use if/else statements inside a case, every possible branch must contain a jump statement. If one branch (e.g., the else) allows execution to reach the bottom of the case, the error occurs.
Example of error
public void CheckAdmin(string role, bool isActive)
{
switch (role)
{
case "Admin":
if (isActive)
{
Console.WriteLine("Welcome Admin");
return; // Exits method (Valid)
}
// ⛔️ Error CS0163: What if 'isActive' is false?
// The code falls out of the 'if' and hits the bottom of 'case "Admin"',
// trying to fall into 'default'.
default:
Console.WriteLine("Access Denied");
break;
}
}Solution: Cover All Paths
Ensure the loop or condition has a definitive exit for all scenarios.
public void CheckAdmin(string role, bool isActive)
{
switch (role)
{
case "Admin":
if (isActive)
{
Console.WriteLine("Welcome Admin");
return;
}
else
{
Console.WriteLine("Inactive Admin");
break; // ✅ Correct: The 'else' path now breaks properly
}
default:
Console.WriteLine("Access Denied");
break;
}
}Solution 1: Explicit Fall-Through (goto case)
If you actually want the logic to execute Case A and then immediately execute Case B (the behavior of C++ fall-through), you must be explicit using goto case.
public void ProcessPayment(int status)
{
switch (status)
{
case 1: // "Authorized"
Console.WriteLine("Payment Authorized.");
// We want to proceed immediately to "Capture" logic (Case 2)
// ✅ Correct: Explicitly jump to case 2
goto case 2;
case 2: // "Captured"
Console.WriteLine("Payment Captured.");
break;
}
}Solution 2: Stacked Cases (Empty Cases)
There is one exception to the rule: Empty case labels are allowed to fall through. This allows you to group multiple inputs that should execute the exact same code.
public void CheckDay(string day)
{
switch (day)
{
// ✅ Correct: These cases are empty, so they fall through to "Sunday".
case "Saturday":
case "Sunday":
Console.WriteLine("It's the weekend!");
break;
default:
Console.WriteLine("Work day.");
break;
}
}Conclusion
CS0163 enforces intention. It prevents you from accidentally running code you didn't mean to.
- Standard Case: Always end a non-empty case with
break;orreturn;. - Grouping Inputs: Use stacked empty cases (
case 1: case 2:) to share logic. - Sharing Logic: If you need to run one case and then another, use
goto case <val>;.