Your static analyzer has flagged a condition as always false. The warning looks like one of these, depending on your tool:
- SonarQube: “Conditional expressions which are always true or false can lead to unreachable code” (RSPEC-2583)
- IntelliJ / Inspectopedia: “Code is not analyzed because condition is statically evaluated as false”
- Checkmarx / Fortify: “Unreachable code, dead branch detected”
- ESLint: “no-constant-condition, unexpected constant condition”
- Pylint: “W0125: Using a conditional statement with a constant value”
All of these are saying the same thing: the analyzer has proven, at analysis time, without running the code, that a specific branch of a conditional statement can never execute. The condition that guards that branch is always false. Everything inside that branch is dead code.
This guide covers what causes these warnings, how to identify which category each warning falls into, the correct resolution for each category, when suppression is appropriate, and what always-false conditions in legacy COBOL code reveal about migration scope.
Retired Business Rules Still in Your Code
SMART TS XL identifies EVALUATE branches referencing product codes, status values, and customer types that no longer exist in production data.
FIND OUT MORE…How Static Analysis Detects Always-False Conditions
Modern static analyzers use symbolic execution and data flow analysis, not simple pattern matching, to detect always-false conditions. The analyzer tracks the possible values of each variable at every point in the program. When it reaches a conditional, it evaluates whether the condition can ever be true given the known constraints on the variables.
Three primary mechanisms produce always-false detection:
Symbolic execution. The analyzer assigns symbolic values to variables and tracks how operations constrain those values. If variable x is assigned 0 on line 3 and compared x > 10 on line 7 with no intervening assignment, the condition is provably false.
Type system constraints. Some conditions are impossible given the type of the variable. Comparing a non-null object reference to null after a non-null assertion, or comparing an enum value to a case outside its defined set.
Boolean algebra simplification. Compound conditions that simplify to false regardless of variable values: (a && !a), (x > 10 && x < 5), (!flag || false).
SonarQube’s rule RSPEC-2583 specifically uses symbolic execution: it tracks the state of variables through the control flow graph and flags conditions where the symbolic state makes the condition provably false. IntelliJ’s “condition statically evaluated as false” warning uses the same approach.
The Four Root Causes
Correctly resolving an always-false warning depends on correctly identifying which of the four root causes applies. The resolution differs for each.
Root Cause 1: Logical Contradiction
The condition contains a logical impossibility, two subconditions that cannot both be true simultaneously, or a compound condition that reduces to false by boolean algebra.
java
// Example: mutually exclusive subconditions
int score = getScore();
if (score > 90 && score < 50) { // Always false: no integer is both > 90 and < 50
applyBonus(); // Never executes
}
// Example: boolean tautology negation
boolean active = isActive();
if (active && !active) { // Always false: a && !a = false
sendNotification(); // Never executes
}
// Example: range check already guaranteed
if (value >= 0) {
if (value < 0) { // Always false: already know value >= 0
handleNegative(); // Never executes
}
}
Resolution: Fix the logic. Either the condition contains a typo (the developer meant score > 90 || score < 50) or the branch should be removed. In the range check example, the inner if is redundant and should be deleted.
Root Cause 2: Accumulated Business Rule Changes
This is the most significant cause in long-lived codebases. A condition that was valid and meaningful when it was written has become permanently false due to subsequent changes in the code around it, without anyone removing the now-dead branch.
java
// 2018: processType could be A, B, or C
// 2023: type C was deprecated and removed from the system
// The processType field is now guaranteed to never equal "C"
// but nobody removed the branch that handled it
public void process(String processType) {
if (processType.equals("A")) {
handleTypeA();
} else if (processType.equals("B")) {
handleTypeB();
} else if (processType.equals("C")) { // Always false since 2023
handleTypeC(); // 47 lines of dead business logic
}
}
python
# Python equivalent: accumulated rule changes
def calculate_rate(customer_tier: str) -> float:
if customer_tier == "GOLD":
return 0.05
elif customer_tier == "SILVER":
return 0.03
elif customer_tier == "BRONZE":
# BRONZE tier was eliminated in Q2 2021
# All BRONZE customers were migrated to SILVER
# This branch has been dead for 4+ years
return 0.01 # Never executes
return 0.0
Resolution: Verify the business context, then remove the dead branch entirely. The business rule that made the condition possible has changed. The code that implemented it is no longer needed. Document the removal in the commit message: “Removed BRONZE rate branch, tier eliminated Q2 2021, all customers migrated to SILVER.”
Root Cause 3: Defensive Programming for Future-Proofing
Some always-false conditions are intentional, the developer wrote them knowing the condition cannot currently be true, as a defensive guard against future code changes that might make it true.
java
// SonarQube RSPEC-2583 explicitly exempts these:
final boolean DEBUG_MODE = false;
if (DEBUG_MODE) { // Always false -- intentional
dumpDiagnostics(); // Not unreachable in intent, only in fact
}
// Type narrowing that appears redundant
String value = getValue();
if (value == null || value.isEmpty()) {
return;
}
// At this point, static analysis knows value is non-null and non-empty
if (value == null) { // Always false -- already checked above
throw new IllegalStateException(); // Defensive guard
}
SonarQube RSPEC-2583 explicitly carves out an exception: “When the condition is a single final boolean” or “when the condition is literally true or false”, these are treated as intentional and not flagged.
Resolution: If the condition is a debug flag or compile-time constant: leave it and add a suppression annotation if the tool flags it. If it is a defensive null-check or range guard that feels redundant but is genuinely protective: restructure the code to make the protection explicit at a different level, or suppress with a documented justification.
Root Cause 4: Tool False Positives from Runtime Configuration
Static analyzers cannot see runtime configuration, environment variables, reflection, annotation processing, or dependency injection. Code that appears always-false to the analyzer may be reachable through a runtime mechanism the analyzer cannot model.
java
// IntelliJ / Inspectopedia note: "This may cause false-positives if any kind
// of code postprocessing is used, for example, if an annotation processor
// later replaces the method body with something useful."
@ConditionalOnProperty(name = "feature.experimental", havingValue = "true")
public class ExperimentalFeature {
// This class may appear unreachable if the property is false in the
// test configuration the analyzer uses -- but it IS reachable in prod
}
// Method contract that the analyzer cannot see
void run() {
performAction();
System.out.println("Done"); // IntelliJ flags as unreachable
}
@Contract("-> _") // Tells the analyzer: method does NOT always throw
static void performAction() { throw new AssertionError(); }
Resolution: Add the appropriate method contract annotation (@Contract for IntelliJ, @NotNull/@Nullable for Kotlin, type assertions for TypeScript) to give the analyzer the runtime information it needs. If annotation-based resolution is not available, use the tool’s suppression mechanism with a documented justification.
COBOL: Where Always-False Conditions Reveal Decades of Dead Logic
In COBOL and legacy mainframe systems, always-false conditions have a different character than in modern application code, and a different significance for the teams that maintain or modernize them.
COBOL programs are not refactored the way modern code is. When a business rule changes, a tax code is revised, a product tier is eliminated, a regulatory requirement is updated, the common practice is to add the new logic without removing the old. The old EVALUATE WHEN or IF branch remains in the source, guarded by a condition that can never be true given the current state of the data it processes.
cobol
EVALUATE WS-PRODUCT-TYPE
WHEN 'STD'
PERFORM CALC-STANDARD-RATE
WHEN 'PRM'
PERFORM CALC-PREMIUM-RATE
WHEN 'BAS'
* BAS product type retired June 2009
* All BAS customers converted to STD
* This branch has been dead for 15+ years
PERFORM CALC-BASIC-RATE
WHEN 'LEG'
* LEG (legacy) type eliminated in 2001 system migration
* Should have been removed but was left as "just in case"
PERFORM CALC-LEGACY-RATE
WHEN OTHER
PERFORM HANDLE-UNKNOWN-TYPE
END-EVALUATE.
The two dead branches in this EVALUATE, BAS and LEG, are not errors. They are historical artifacts: business rules that were valid at specific points in the system’s history and became permanently unreachable when those product types were retired. Nobody removed them because nobody was sure whether they might still be needed, and the cost of being wrong seemed higher than the cost of leaving them in place.
What always-false conditions in COBOL reveal:
The dead branches represent business logic that no longer applies. The PERFORM CALC-BASIC-RATE and PERFORM CALC-LEGACY-RATE targets may themselves be entire paragraphs or sections of COBOL code, potentially hundreds of lines each, that are similarly dead. The always-false condition is the entry point to a tree of dead code that propagates through PERFORM relationships.
In a 100,000-line COBOL program, dead branches from retired business rules may account for 20-35% of the total code. That percentage is migration scope that does not need to be converted, tested, or validated in a modernization program. Identifying it before migration planning produces a direct scope reduction, and scope reduction at the planning stage is the highest-value application of always-false condition analysis.
The Resolution Decision Tree
Always-false condition warning received
│
▼
Is this a compile-time constant
or debug flag? (DEBUG = false, etc.)
│
Yes ───┼─── No
│ │
Intentional. ▼
Suppress or Does the condition
leave as-is. contain a logic error?
(a > 10 && a < 5, etc.)
│
Yes ───┼─── No
│ │
Fix the Has the condition
logic bug. become false due to
a past business rule
change?
│
Yes ───┼─── No
│ │
Verify, Could a runtime
then remove mechanism make
the dead it reachable?
branch. │
Yes ──── No
│
Add contract
annotation. Remove the
dead branch.
Suppression: When and How
Suppression is appropriate when the condition is genuinely intentional and the tool cannot be given the contract information to understand why. Suppression is not appropriate as a shortcut to avoid investigating what the warning actually means.
Java (SonarQube):
java
@SuppressWarnings("java:S2583")
if (DEBUG_MODE) { // Intentional: compile-time debug flag
dumpState();
}
Java (IntelliJ):
java
//noinspection ConstantConditions
if (possiblyNull != null) { // Analyzer cannot see the runtime injection
process(possiblyNull);
}
Python (Pylint):
python
if False: # pylint: disable=W0125
# Intentional: placeholder for future implementation
pass
C# (SonarQube):
csharp
#pragma warning disable S2589
if (IsDebugBuild) { // Compile-time constant -- intentional
LogDiagnostics();
}
#pragma warning restore S2589
COBOL (SMART TS XL / custom suppression comment):
cobol
*>> SUPPRESS UNREACHABLE: BAS branch retained for audit trail
WHEN 'BAS'
PERFORM CALC-BASIC-RATE
Suppression discipline: Every suppression should be accompanied by a comment that explains why the condition is intentional, not just that it is being suppressed. A suppression comment that says
// suppress unreachableis worse than no suppression, it hides the warning without explaining why the warning is wrong. A suppression that says// suppress: DEBUG_MODE is a compile-time constant, branch is retained for IDE visibilityis acceptable.
How SMART TS XL Identifies Always-False Conditions at Portfolio Scale
SMART TS XL’s static code analysis applies data flow and control flow analysis across COBOL, JCL, Java, Python, and every other language in the environment to identify conditions that are statically provable as always-false, at portfolio scale, across thousands of programs simultaneously, not one file at a time in a developer IDE.
For COBOL portfolios specifically, this means: every EVALUATE WHEN clause and every IF condition in every program is analyzed against the known constraints on the data that flows into it. Conditions that reference product codes, status flags, or type codes whose valid value sets have changed over the program’s history are flagged as potential dead branches. The output is a dead code inventory: every program, every dead branch, and the estimated line count of dead code reachable from each always-false condition.
The legacy modernization analysis converts this inventory into a scope reduction: every dead branch is excluded from the migration specification before any conversion effort begins. A program that appears to have 2,000 lines of business logic may have 600 lines of dead business logic from retired product types, eliminated customer tiers, and deprecated calculation paths. Migrating 1,400 lines instead of 2,000 lines is a 30% scope reduction on that program, and the dead branches are the highest-risk part of the scope to migrate, because nobody knows what they were supposed to do in the first place.
The enterprise search capability makes the always-false inventory queryable: find every COBOL program that contains an EVALUATE WHEN clause referencing a product code not in the current product catalog, every program that checks for a status flag value that has not existed in the database since a specific year, every IF condition that references a data structure field that has been repurposed since the condition was written. These queries produce the targeted dead code inventory that manual code review would take months to produce across a large COBOL portfolio.
The Warning Is Usually Right
Static analysis warnings for always-false conditions are, in the majority of cases, accurate findings. The condition is always false. The branch never executes. The code inside it is dead.
The appropriate response is not suppression, it is investigation. Which root cause applies? Logical contradiction, accumulated business rule change, intentional defensive programming, or tool false positive from runtime configuration? Each has a correct resolution. Three of the four result in removing the dead code. One results in suppressing with justification.
For legacy COBOL systems, always-false condition analysis at portfolio scale is not primarily a code quality exercise, it is a scope reduction exercise. The dead branches that accumulate over decades of business rule changes represent migration effort that should not be committed. Finding them before the migration plan is locked is the highest-value application of always-false condition analysis for any team planning a COBOL modernization program.
The analyzer is telling you something true. Listen to it.


