Recently I spent more time than I’d like to admit debugging a validation that kept triggering in a case where it should have stayed quiet.
The code looked fine.
The fields were correct.
The syntax was clean.
But the logic was wrong and the root cause was a small thing I had not thought about in a while: how ABAP evaluates AND and OR when you don’t use parentheses.
This post is just me documenting that mistake, so I don’t repeat it - and hopefully you don’t either.
The Rule I Wanted
I had three logical conditions in my head:
-
lv_change_mode- we are in “change” mode, not “create” -
lv_flag_missing- a flag marked when some required data is missing -
lv_prev_failed- the previous step (say a BAPI call or check) failed
The business rule was:
Only in change mode, if either the data is missing or the previous step failed, then raise an error.
In plain words:
-
If we are changing an existing data
-
And either the required data is incomplete or the earlier step already failed
-
Then this validation should stop the user to process further
The Correct Condition
In ABAP, the condition should look like this:
IF lv_change_mode = abap_true
AND ( lv_flag_missing = abap_true
OR lv_prev_failed = abap_true ).
" Raise error
ENDIF.
Read it like this:
-
Change mode is active
-
And (required data is missing OR previous step failed)
-
Then error
This matches the business rule exactly.
The Mistake: Missing Parentheses
While refactoring, I “simplified” the condition and wrote:
IF lv_change_mode = abap_true
AND lv_flag_missing = abap_true
OR lv_prev_failed = abap_true.
" Raise error
ENDIF.
At a glance this still feels like:
change mode AND (required data missing OR prev failed)
But that’s not how ABAP reads it.
How ABAP actually evaluates it
In ABAP and basically in most programming languages, AND has higher precedence than OR.
So the runtime sees this:
( lv_change_mode = abap_true
AND lv_flag_missing = abap_true )
OR lv_prev_failed = abap_true
The part with OR lv_prev_failed is now standing on its own, outside of the “change mode” check.
That is exactly where things went wrong.
The Scenario That Exposed the Bug
Here is the exact kind of case where my validation behaved incorrectly.
Situation
-
We are in create mode, not change
lv_change_mode = abap_false -
The required data is filled (Data is not missing)
lv_flag_missing = abap_false -
The previous step failed with an error
lv_prev_failed = abap_true
From the business perspective:
-
We don’t even want this validation in create mode.
-
Whatever happened in the previous step, this particular check should not block the user here.
So the expected outcome is: no error.
What the correct condition does for create mode
Using the correct version:
IF lv_change_mode = abap_true
AND ( lv_flag_missing = abap_true
OR lv_prev_failed = abap_true ).
" error
ENDIF.
Evaluate it:
-
lv_change_mode = abap_true→FALSE -
( lv_flag_missing = abap_true OR lv_prev_failed = abap_true )→FALSE OR TRUE→TRUE
Overall:
FALSE AND TRUE = FALSE
So the IF condition is not satisfied.
No error is raised.
This is exactly what we want.
What the incorrect condition does in create mode
Now look at the version without parentheses:
IF lv_change_mode = abap_true
AND lv_flag_missing = abap_true
OR lv_prev_failed = abap_true.
" error
ENDIF.
ABAP evaluates it as:
( lv_change_mode = abap_true
AND lv_flag_missing = abap_true )
OR lv_prev_failed = abap_true
Substitute the values:
-
lv_change_mode = abap_true→FALSE -
lv_flag_missing = abap_true→FALSE -
lv_prev_failed = abap_true→TRUE
Now:
( FALSE AND FALSE ) OR TRUE = FALSE OR TRUE = TRUE
The condition becomes true.
The error is raised.
And that’s the bug:
The validation is now firing in create mode just because lv_prev_failed is true, even though it was supposed to run only in change mode.
One missing pair of parentheses moved lv_prev_failed outside of the “change mode” guard.
What This Has To Do With My Real Issue
In my real code, the variables were different (linked to Material data), but the pattern was the same:
-
A condition like:
A AND (B OR C) -
Was accidentally written as:
A AND B OR C -
ABAP read it as:
(A AND B) OR C -
And that last
OR Ccondition made the IF true in cases where I did not want it to run
The code was syntactically fine.
The bug was purely logical and driven by operator precedence.
Takeaways
-
In ABAP,
ANDis evaluated beforeOR. -
Any time you mix
ANDandORin the same IF condition, add parentheses to make the logic explicit. -
When a validation fires “sometimes, but not always”, and the fields look correct, your first suspect should be the IF condition.
This was a very small mistake, but in a validation-heavy program it can completely change the business behaviour. I’m writing this down because the next time I type AND ... OR in one IF, I want a small alarm bell to ring in my head.
