OData Gateway
Architect / Cross-trackadvanced

OData Gateway Part 9: Error Handling and the Message Container

Key takeaway

Return meaningful errors from Gateway services: business vs technical exceptions and their HTTP status codes, the message container for BAPI and T100 messages, leading messages and error details, success and warning messages in the sap-message header, and what Fiori shows to the user.

Explanation

📌 KEY POINTS
✅ /IWBEP/CX_MGW_BUSI_EXCEPTION = business error the user can fix (default HTTP 400); /IWBEP/CX_MGW_TECH_EXCEPTION = technical failure (HTTP 500).

✅ The message container (mo_context->get_message_container( )) collects T100/BAPI messages; raising the exception with message_container returns them as error details in the response.

✅ Success and warning messages without an error can be sent in the sap-message HTTP header (iv_add_to_response_header = abap_true); Fiori elements shows them as toasts or message popovers.

⚠️ Swallowing BAPI errors (ignoring RETURN) or raising a generic "Error occurred" makes the app useless to users and support — always pass the real message through.

━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE

Part 8 changed data. Now errors must reach the user clearly.

━━━━━━━━━━━━━━━━━━━━
▶ 1. EXCEPTION TYPES

  • Business: validation failed, record locked, not found (textid resource_not_found → 404), no authorization.
  • Technical: unexpected state, RFC failure, programming errors.
  • Optional parameter http_status_code to set a specific code (e.g. 409 conflict, 403 forbidden).

━━━━━━━━━━━━━━━━━━━━
▶ 2. MESSAGE CONTAINER

  • lo_msg = mo_context->get_message_container( ).
  • add_messages_from_bapi( it_bapi_messages = lt_return … ) — all BAPIRET2 lines.
  • add_message( iv_msg_type, iv_msg_id, iv_msg_number, iv_msg_v1 … ) — T100 message.
  • add_message_text_only( iv_msg_type = 'E' iv_msg_text = … ).
  • Leading message: the first/most important error becomes the main "message"; others go to innererror/errordetails.

━━━━━━━━━━━━━━━━━━━━
▶ 3. RESPONSE STRUCTURE (JSON)

  • error.code (message class/number), error.message.value (leading text), error.innererror.errordetails[] (all messages with severity and target).
  • Fiori shows the leading message and details in the message popover.

━━━━━━━━━━━━━━━━━━━━
▶ 4. SUCCESS AND WARNING MESSAGES

  • Add messages with iv_add_to_response_header = abap_true and do not raise; they appear in the sap-message header.
  • Example: "Order 4711 saved" or "Credit limit almost reached".

━━━━━━━━━━━━━━━━━━━━
▶ 5. RULES

  • Map BAPI RETURN types E/A to an exception, W/S to header messages.
  • Keep messages in T100 message classes for translation.
  • Never expose stack traces or SQL errors to users; log technical details (application log, Part 10).
  • In $batch changesets, an error in one operation rolls back the whole changeset.

━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP

  1. Create message class ZSALES with messages for validation errors.
  2. In CREATE_ENTITY, call a BAPI and pass its RETURN to the container on error.
  3. On success, add a success message to the response header.
  4. Test in /IWFND/GW_CLIENT: look at the response body and the sap-message header.

✅ CHECKPOINT: every error in your service reaches the user with a clear, translatable message and the right HTTP status.

Code example

ABAP Code
* ===== STEP 1: DPC_EXT - create with BAPI and message container =====METHOD salesorderset_create_entity.   DATA: ls_in     TYPE zcl_zsales_mpc=>ts_salesorder,        lt_return TYPE STANDARD TABLE OF bapiret2,        ls_return TYPE bapiret2,        lv_vbeln  TYPE vbeln_va,        lo_msg    TYPE REF TO /iwbep/if_message_container.   io_data_provider->read_entry_data( IMPORTING es_data = ls_in ).  lo_msg = mo_context->get_message_container( ). * ===== STEP 2: own validation with T100 message =====  IF ls_in-customer IS INITIAL.    lo_msg->add_message( iv_msg_type   = 'E'                         iv_msg_id     = 'ZSALES'                         iv_msg_number = '001' ).      "Customer is mandatory    RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception      EXPORTING message_container = lo_msg.  ENDIF. * ===== STEP 3: call BAPI (parameters shortened) =====*  CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'*    EXPORTING order_header_in = ls_header*    IMPORTING salesdocument   = lv_vbeln*    TABLES    return          = lt_return  order_items_in = lt_items*              order_partners  = lt_partners. * ===== STEP 4: errors -> exception with all messages (HTTP 400) =====  LOOP AT lt_return INTO ls_return WHERE type = 'E' OR type = 'A'.    EXIT.  ENDLOOP.  IF sy-subrc = 0.    CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.    lo_msg->add_messages_from_bapi(      it_bapi_messages         = lt_return      iv_determine_leading_msg = /iwbep/if_message_container=>gcs_leading_msg_search_option-first ).    RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception      EXPORTING message_container = lo_msg.  ENDIF.   CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'    EXPORTING wait = 'X'. * ===== STEP 5: success message in sap-message header =====  lo_msg->add_message( iv_msg_type               = 'S'                       iv_msg_id                 = 'ZSALES'                       iv_msg_number             = '010'   "Order &1 created                       iv_msg_v1                 = lv_vbeln                       iv_add_to_response_header = abap_true ).   ls_in-salesorder = lv_vbeln.  er_entity = ls_in. ENDMETHOD. * ===== STEP 6: technical problem example (HTTP 500) =====*  RAISE EXCEPTION TYPE /iwbep/cx_mgw_tech_exception*    EXPORTING textid = /iwbep/cx_mgw_tech_exception=>internal_error.

Real project scenario

Users of a Fiori order app saw only "An error occurred" when saving. Support had to reproduce every case in VA01 to find the reason, typically a missing partner function or blocked material.
The DPC_EXT code checked RETURN but raised a busi exception with a fixed text. The developer replaced it with add_messages_from_bapi and a leading-message option, moved own validation texts into message class ZSALES, and added a success message with the order number in the sap-message header. Save-related tickets dropped by more than half within a month.

Common mistakes

  • Ignoring the BAPI RETURN table.
  • Raising a generic hard-coded error text.
  • Using technical exceptions (500) for business validation errors.
  • Hard-coded English texts instead of message classes.
  • Committing even though errors were returned.

Best practices

  • Business errors → busi exception with message container.
  • Pass all BAPI messages, pick a clear leading message.
  • Success/warnings via sap-message header.
  • T100 messages for translatable texts.
  • Log technical details, show user-friendly messages.

Interview angle

Questions: "How do you return BAPI errors from OData?", "Busi vs tech exception?", "How do you send a success message?"
Strong answer: message container from mo_context, add_messages_from_bapi or add_message, raise /iwbep/cx_mgw_busi_exception with message_container (400; leading message + errordetails). Tech exception for technical failures (500); http_status_code for specific codes. Success/warning messages with iv_add_to_response_header into the sap-message header, shown by Fiori.

Practice this lesson

Quick check

1. A BAPI called in CREATE_ENTITY returns type E messages. What should the method do?

2. How can a Gateway service return a success message like "Order 4711 created" without raising an error?

3. Which exception class and HTTP status fit an unexpected technical failure, such as a failed RFC connection?

Interview questions

1. OData call returns 500 error with no useful message. What do you check?

Answer it in your own words first, then compare.

2. A sales order service uses MESSAGE e001(zsales) for validation in DPC_EXT. Fiori users get a short dump or a generic error. How do you fix error handling?

Answer it in your own words first, then compare.

Practice more with Interview AI →

Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.

More lessons in this topic

Interview questions on this topic

Related SAP topics