Determinations and Validations in RAP Behavior Implementations
Determinations are behavior implementation methods that derive or default field values and are allowed to write data; validations are methods that check business rules and are only allowed to raise messages, never to change data. Both run inside the transactional save sequence, triggered either on modify or on save, and confusing which one may write is the single most common implementation error.
This page covers how determinations and validations are declared and implemented in a RAP behavior definition, the difference in what each is permitted to do, and the ordering and triggering rules that decide when they fire during the save sequence. It focuses on the practical failures: infinite retrigger loops, misuse of validations for derivation, and performance cost on mass changes.
Published 16 Sept 2026· 1,535 words
What it is
A determination is a method bound to an entity that runs automatically during the save sequence and is allowed to modify instance data, typically to default a status, generate a number, or recalculate a derived total. A validation is a method bound the same way but restricted to reading data and raising messages against the instance; it cannot write. Both are declared in the behavior definition with a trigger time, either ON MODIFY, meaning immediately after the triggering operation inside the current transaction, or ON SAVE, meaning during the finalize and check phase before the transaction commits. The structural fact that causes most confusion is this write restriction: developers used to classic BAdI or user-exit style coding instinctively reach for a validation when they actually need a determination, then discover the compiler or runtime rejects the modifying statement, or worse, the change is silently lost because it executed in the wrong phase.
When to use it
Use a determination whenever a field value should be computed from other fields or from related instances without the user or caller supplying it: line totals from quantity and price, a generated document number, a default currency, a status flag set the first time an instance is created. Use a validation whenever the check is a business rule that should block or warn on save without altering anything: date range consistency, mandatory combinations of fields, referential checks against a partner entity. The mistake to avoid is putting expensive cross-entity lookups into an ON MODIFY determination that fires on every keystroke-level update from the UI, and the opposite mistake of trying to silently correct bad data inside a validation, which is not possible and forces the check into a determination that both fixes and then separately validates, doubling the maintenance surface for no benefit.
How it fits the stack
Determinations and validations live inside the behavior implementation class of a RAP business object, alongside action and mapping implementations. They are invoked by the RAP runtime as part of the save sequence it orchestrates, not called directly by application code, and internally they read and sometimes write instance data using entity manipulation language against the same buffer that actions and CREATE or UPDATE operations touch. Above this layer sits the exposed business object and its OData service, which trigger the save sequence indirectly whenever a client commits changes; below sits the persistence layer that the runtime writes to only after all determinations and validations have passed. They replace the scattered FEATURE, CHECK, and DETERMINE implementations of classic BOPF, and the ad hoc validation code that used to live inside BAPI wrapper function modules in unmanaged scenarios, centralizing both concerns as declared, framework-triggered methods instead of manually called subroutines.
A worked example
A travel booking business object holds a header entity for the trip and a child entity for individual bookings. A determination declared ON SAVE for the header recalculates the total travel price whenever any child booking is created, changed, or deleted, reading all associated bookings via an association and writing the summed amount back to the header instance through a modify operation inside the determination method. A separate validation, also ON SAVE, checks that the trip's begin date is earlier than its end date and that the overall status is not being set to 'booked' while any child booking is still in status 'open'; on failure it raises an instance-bound error message pointing at the begin date field so the Fiori Elements object page highlights the correct control. The determination is scoped to trigger only when price-relevant fields change, avoiding a rerun every time an unrelated header field like a free-text comment is updated. The validation reads data only and never attempts to correct the dates itself, leaving that responsibility to the caller or to a separate default-setting determination on create.
How to choose
- Does the logic change data or only judge it: if it writes anything, it belongs in a determination, never in a validation, regardless of how small the change looks.
- ON MODIFY versus ON SAVE: ON MODIFY gives immediate feedback within the same transaction and lets later steps see the derived value, but it fires on every relevant change including intermediate draft edits, so it costs more on high-frequency UI interaction; ON SAVE runs once at commit time and is usually the right default for anything that does not need to be visible mid-transaction.
- Field scoping: always restrict a determination or validation to the specific fields that should trigger it, otherwise an unrelated field change reruns expensive logic or, worse, a determination that writes one of its own trigger fields causes a retrigger loop.
- Message severity and target: decide whether a failed validation should be an error that blocks save or a warning that lets the user proceed, and set the message's target key precisely, since a wrong target means the message appears detached from the field it concerns in the Fiori UI.
- Composition scope: a validation on a child entity generally cannot see sibling or parent data without an explicit association read, so decide early whether the rule genuinely belongs on the child or should be centralized on the parent where the full picture is available.
- Volume and mass processing: for BOs used in mass upload or integration scenarios, prefer ON SAVE and minimize per-instance lookups inside the method body, since determinations and validations run per affected instance and an inefficient implementation that is invisible in unit testing becomes a bottleneck at production data volumes.
Common pitfalls
- A determination writes to one of the fields listed in its own trigger condition, causing the runtime to schedule it again, which either loops or is silently deduplicated in a way that hides a logic bug until a specific data pattern exposes it.
- A validation attempts to correct or default a field to make the check pass; this either fails to compile or has no effect at runtime, because validations are read-only by design.
- Developers assume validations run continuously as the user types, when in fact they typically fire only at the save or check phase, so a rule that should give live feedback in a Fiori Elements object page needs a different mechanism, such as a field-level determination or client-side check.
- An ON MODIFY determination that performs a database read for every keystroke-level change performs acceptably in the IDE with a handful of test records and then becomes a measurable delay in production when hundreds of rows are edited in a list report.
- Message target keys pointing at the wrong entity or field make the error text appear at the top of the object page instead of next to the offending field, which passes functional testing quickly but frustrates end users and generates support tickets.
- Extending a standard RAP business object with a custom determination or validation without checking what standard logic already runs at the same trigger time, leading to two pieces of logic fighting over the same field or duplicating a check that already exists.
ECC, S/4HANA and clean core
Determinations and validations are a core, fully supported part of the RAP programming model on S/4HANA and fit cleanly within clean core extensibility guidance, since they are declared in the behavior definition and implemented in ABAP classes that live in the customer or partner namespace without touching SAP standard code. There is no discouragement of the pattern itself; the caution is architectural, not technical: logic that used to sit in classic BOPF determinations, BAdI checks, or BAPI wrapper validations does not migrate automatically and has to be re-analyzed and re-implemented against the new trigger model, including deciding afresh which checks are still relevant given the new entity structure and which fields actually exist in the CDS-based data model.
Whose problem this is
Implementation is a developer task inside the behavior implementation class, but the business rule itself, including which fields matter, what message text is shown, and whether a failure should block or warn, comes from functional consultants who own the process. An architect should sign off on the split between determination and validation and the choice of trigger time before implementation starts, since retrofitting that decision later means reworking field scoping across the whole business object.
Related SAP objects
Reviewed pages this object connects to in the ERPClimb knowledge graph.
Source: ERPClimb — https://erpclimb.com/sap-technical-topics/determinations-and-validations-in-rapERPClimb is an independent platform and is not affiliated with SAP SE. Reference pages are written and reviewed by SAP consultants for learning and troubleshooting.