본문 바로가기
디버깅 & 트러블슈팅

[SAP ABAP] BAPI · BDC 에러 메시지 확인 방법 — MESSAGE INTO · FORMAT_MESSAGE 빌드 (BAPIRET2 · BDCMSGCOLL)

by Song.sh 2026. 5. 21.

SAP 에서 BAPI 나 BDC 호출 후 에러를 확인하려고 보면, RETURN 테이블의 메시지 행이 평문이 아니라 메시지 ID + 번호 + 변수 형태로만 담겨 있어 그대로는 사용자에게 보여줄 수 없는 경우가 많습니다. 예시: ID = 'M7' · NUMBER = '060' · V1 = '10'. 사용자에게 "총 금액과 잔액이 일치하지 않습니다" 같은 완성된 문장을 보여주려면 이 메시지 ID + 번호로 메시지 마스터(T100) 에서 텍스트를 가져와 변수를 치환해야 합니다.

 

이 글에서는 BAPI 의 BAPIRET2 와 BDC 의 BDCMSGCOLL 메시지 구조를 비교하고, 3가지 메시지 빌드 방법 (MESSAGE ... INTO 구문 · FORMAT_MESSAGE FM · MESSAGE_TEXT_BUILD FM) 의 차이·활용·함정을 정리합니다. 실무에서 BAPI / BDC 인터페이스의 에러 로그 로직을 한 번에 표준화하는 데 사용 가능합니다.

핵심 — BAPIRET2 vs BDCMSGCOLL 비교

BAPI 와 BDC 는 에러를 담는 구조체가 다르지만 메시지 ID + 번호 + 변수 4개 라는 공통 골격을 공유합니다. 필드명만 약간 다를 뿐 빌드 방식은 동일합니다.

의미 BAPIRET2 (BAPI) BDCMSGCOLL (BDC)
메시지 유형 TYPE (E·W·S·I·A) MSGTYP
메시지 클래스 (ID) ID MSGID
메시지 번호 NUMBER MSGNR
완성된 텍스트 (있을 때만) MESSAGE 없음 — 직접 빌드 필수
변수 1~4 MESSAGE_V1 ~ V4 MSGV1 ~ MSGV4

핵심 차이는 BAPIRET2 에는 MESSAGE 필드가 있어 변환된 텍스트가 담겨 올 때도 있지만, BDCMSGCOLL 은 100% 직접 빌드 가 필요하다는 점입니다. BAPI 도 표준 / 비표준 구현에 따라 MESSAGE 가 비어 있는 경우가 자주 있어 항상 직접 빌드하는 패턴을 기본으로 잡는 것이 안전 합니다.


1단계 — MESSAGE INTO 구문 (가장 표준)

ABAP 표준의 MESSAGE ... INTO 구문을 사용하면 별도 FM 호출 없이 바로 메시지 텍스트를 빌드할 수 있습니다. SAP 표준에서 권장하는 방법입니다.

DATA: lv_msg TYPE string,
      ls_return TYPE bapiret2.

LOOP AT lt_return INTO ls_return WHERE type CA 'EAW'.

  MESSAGE ID     ls_return-id
          TYPE   ls_return-type
          NUMBER ls_return-number
          WITH   ls_return-message_v1
                 ls_return-message_v2
                 ls_return-message_v3
                 ls_return-message_v4
          INTO   lv_msg.

  WRITE: / lv_msg.

ENDLOOP.

INTO 절을 붙이면 메시지를 화면에 띄우지 않고 변수에만 담깁니다. 인터페이스 / 배치에서 사용자에게 띄울 일이 없을 때 안전한 방식입니다.

장점 — ABAP 키워드라 별도 FM 의존성 없고, 메시지 클래스의 &1·&2·&3·&4 위치를 자동 치환.


2단계 — FORMAT_MESSAGE FM (가장 흔한 패턴)

레거시 코드에서 가장 자주 보이는 패턴. FORMAT_MESSAGE Function Module(Function Group SPOO) 을 호출합니다.

DATA: lv_msg TYPE string,
      ls_return TYPE bapiret2.

LOOP AT lt_return INTO ls_return WHERE type CA 'EAW'.

  CALL FUNCTION 'FORMAT_MESSAGE'
    EXPORTING
      id   = ls_return-id
      lang = sy-langu
      no   = ls_return-number
      v1   = ls_return-message_v1
      v2   = ls_return-message_v2
      v3   = ls_return-message_v3
      v4   = ls_return-message_v4
    IMPORTING
      msg  = lv_msg
    EXCEPTIONS
      not_found = 1
      OTHERS    = 2.

  IF sy-subrc = 0.
    WRITE: / lv_msg.
  ENDIF.

ENDLOOP.

내부에서 T100 메시지 마스터를 조회한 후 변수를 치환합니다. LANG 파라미터로 다국어 메시지를 가져올 수 있습니다('K' = 한국어 · 'E' = 영어). 기본값 '-D' 는 사용자 로그인 언어 + Default 순서로 시도합니다.


3단계 — BDC 에러 처리 (BDCMSGCOLL 패턴)

BDC 호출 후 CALL TRANSACTION ... MESSAGES INTO 로 메시지를 수집합니다.

DATA: lt_bdcdata TYPE TABLE OF bdcdata,
      lt_msgcol  TYPE TABLE OF bdcmsgcoll,
      ls_msgcol  TYPE bdcmsgcoll,
      lv_msg     TYPE string.

" ... BDC 데이터 빌드 ...

CALL TRANSACTION 'MM02'
  USING    lt_bdcdata
  MODE     'N'                   " N = No display
  UPDATE   'S'                   " S = Synchronous
  MESSAGES INTO lt_msgcol.

LOOP AT lt_msgcol INTO ls_msgcol WHERE msgtyp CA 'EAW'.

  MESSAGE ID     ls_msgcol-msgid
          TYPE   ls_msgcol-msgtyp
          NUMBER ls_msgcol-msgnr
          WITH   ls_msgcol-msgv1
                 ls_msgcol-msgv2
                 ls_msgcol-msgv3
                 ls_msgcol-msgv4
          INTO   lv_msg.

  " 로그 적재
  APPEND VALUE #(
    type    = ls_msgcol-msgtyp
    message = lv_msg
    msgid   = ls_msgcol-msgid
    msgnr   = ls_msgcol-msgnr
  ) TO lt_error_log.

ENDLOOP.

핵심은 MESSAGES INTO 옵션을 빠뜨리면 메시지가 수집되지 않는다 는 점입니다. BDC 가 에러를 내도 호출자에게 전달되지 않으므로 디버깅이 어려워집니다. 모든 BDC 호출에는 이 옵션을 표준으로 박아두시기 바랍니다.


4단계 — BAPI RETURN 검증 + 메시지 빌드 표준 패턴

BAPI 호출 후 RETURN 을 일관성 있게 처리하는 표준 패턴.

DATA: lt_return TYPE TABLE OF bapiret2,
      ls_return TYPE bapiret2,
      lv_msg    TYPE string,
      lt_log    TYPE TABLE OF ty_log,
      ls_log    TYPE ty_log,
      lv_has_error TYPE abap_bool.

" ... BAPI 호출 ...
CALL FUNCTION 'BAPI_MATERIAL_SAVEDATA'
  EXPORTING
    headdata = ls_head
  IMPORTING
    return   = ls_return                " BAPI 마다 다름: 일부는 TABLES
  TABLES
    return   = lt_return.

" 에러 / 워닝 모두 수집
LOOP AT lt_return INTO ls_return.

  " 메시지 빌드
  IF ls_return-message IS NOT INITIAL.
    lv_msg = ls_return-message.         " 이미 빌드된 텍스트가 있으면 그대로
  ELSE.
    MESSAGE ID     ls_return-id
            TYPE   ls_return-type
            NUMBER ls_return-number
            WITH   ls_return-message_v1
                   ls_return-message_v2
                   ls_return-message_v3
                   ls_return-message_v4
            INTO   lv_msg.
  ENDIF.

  " 로그 적재
  ls_log-type    = ls_return-type.
  ls_log-msgid   = ls_return-id.
  ls_log-msgnr   = ls_return-number.
  ls_log-message = lv_msg.
  APPEND ls_log TO lt_log.

  " 에러 플래그
  IF ls_return-type CA 'EA'.
    lv_has_error = abap_true.
  ENDIF.

ENDLOOP.

" 트랜잭션 처리
IF lv_has_error = abap_true.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ELSE.
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
    EXPORTING wait = 'X'.
ENDIF.

4가지 핵심 포인트:

  1. MESSAGE 필드가 채워져 있으면 그대로, 비어 있으면 빌드 (BAPI 마다 동작 다름)
  2. TYPE CA 'EA' 로 에러 + 아보트만 잡고 워닝(W) 은 로그만 적재
  3. ID + NUMBER 까지 로그에 함께 적재 — 메시지 추적용 (다음 단계 참고)
  4. 메시지 1줄이라도 에러면 즉시 ROLLBACK 하고 전체 트랜잭션 폐기

5단계 — 메시지 ID + 번호로 발생 위치 추적 (디버깅)

빌드된 메시지가 무엇을 의미하는지 모를 때 SAP 표준 디버거의 Message 브레이크포인트 로 정확한 발생 위치를 추적할 수 있습니다.

디버거 진입 (예: /h 입력 후 재실행)
 → Breakpoints → Breakpoint at → Message
 → Message Class:  M7
 → Message Number: 060
 → F8 실행 → 그 메시지가 호출되는 표준 코드 라인에서 정지

이 방식은 "왜 이 에러가 발생하는지 모르겠을 때" 가장 빠른 진단 도구입니다. 표준 / 사내 코드 어디에서 메시지가 트리거되는지 정확한 라인이 보이므로 원인 분석이 가능합니다. BAPI / BDC 모두 동일하게 사용.


흔히 빠뜨리는 함정

MESSAGE 필드 빈 채로 사용

BAPI 마다 RETURN 의 MESSAGE 필드 채움 여부가 다릅니다. SAP 표준 BAPI 는 대부분 채워 보내지만, 일부 BAdI 가 호출 끝에 RETURN 만 채우고 MESSAGE 는 비우는 경우가 있습니다. MESSAGE 가 비었으면 빌드 패턴을 기본으로.

워닝 / 에러 혼동

TYPE 5가지 — E 에러, A 아보트, W 워닝, S 성공 / 상태, I 정보. ROLLBACK 트리거는 보통 E + A, 워닝을 에러로 잡으면 정상 트랜잭션까지 폐기됩니다.

BDC 호출에 MESSAGES INTO 누락

CALL TRANSACTION ... MESSAGES INTO 옵션 없이 호출하면 BDC 가 에러를 내도 호출자에게 전달되지 않습니다. 운영 중 BDC 가 조용히 실패하는 가장 흔한 원인.

MODE / UPDATE 옵션 조합

MODE 'N' (no display) + UPDATE 'S' (synchronous) 가 배치 표준. UPDATE 'A' (asynchronous) 는 호출은 빠르지만 직후 SELECT 시 데이터가 안 보일 수 있습니다.

FORMAT_MESSAGE 의 LANG '-D' 기본값

LANG = '-D' 는 "사용자 언어 → Default 언어 순서" 로 시도. 사용자 언어에 메시지 텍스트가 없으면 영문이 나옵니다. 한국어로 고정하려면 명시적으로 LANG = 'K' 전달.

변수 V1~V4 의 자리

메시지 텍스트의 &1·&2·&3·&4 자리에 변수가 치환됩니다. 메시지 클래스에 따라 & 한 개로만 표시되어 있을 수 있는데 그 경우 V1 부터 순서대로 치환됩니다. 변수 누락 시 빈 공간 / 이상한 텍스트로 보이므로 4개 모두 전달하는 것이 안전.

메시지 마스터에서 직접 조회 시도

T100 을 SELECT 해서 메시지 텍스트를 가져온 후 REPLACE '&1' WITH ... 처리하는 코드를 작성하는 경우가 있습니다. 작동은 하지만 표준 함수가 처리하는 멀티 변수 / 언어 fallback / 양식 변환을 다 따라가지 못합니다. 항상 표준 MESSAGE 구문 또는 FORMAT_MESSAGE 를 사용 하시기 바랍니다.

Long Text 가 필요한 경우

T100 의 짧은 텍스트만으로 부족할 때는 메시지의 Long Text(READ TEXT) 를 추가로 조회해야 합니다. SAP Help / 가이드 페이지의 메시지 설명도 이 Long Text 입니다.


전체 코드 — 복사용 통합본 (BAPI + BDC 메시지 로깅)

*&---------------------------------------------------------------------*
*& Report  Z_XX_BAPI_BDC_MESSAGE_LOG
*&---------------------------------------------------------------------*
*& BAPI / BDC 호출 후 에러 메시지 빌드 + 로그 적재 샘플
*&---------------------------------------------------------------------*
REPORT z_xx_bapi_bdc_message_log.

TYPES: BEGIN OF ty_log,
         type    TYPE bapiret2-type,
         msgid   TYPE bapiret2-id,
         msgnr   TYPE bapiret2-number,
         message TYPE string,
       END OF ty_log.

DATA: lt_return    TYPE TABLE OF bapiret2,
      ls_return    TYPE bapiret2,
      lt_bdcdata   TYPE TABLE OF bdcdata,
      lt_msgcol    TYPE TABLE OF bdcmsgcoll,
      ls_msgcol    TYPE bdcmsgcoll,
      lv_msg       TYPE string,
      lt_log       TYPE TABLE OF ty_log,
      ls_log       TYPE ty_log,
      lv_has_error TYPE abap_bool.

* ★ 시나리오 1 — BAPI 호출 + 메시지 처리
" CALL FUNCTION 'BAPI_XXX' ... TABLES return = lt_return.

LOOP AT lt_return INTO ls_return.

  " MESSAGE 필드가 채워졌으면 그대로, 아니면 빌드
  IF ls_return-message IS NOT INITIAL.
    lv_msg = ls_return-message.
  ELSE.
    MESSAGE ID     ls_return-id
            TYPE   ls_return-type
            NUMBER ls_return-number
            WITH   ls_return-message_v1
                   ls_return-message_v2
                   ls_return-message_v3
                   ls_return-message_v4
            INTO   lv_msg.
  ENDIF.

  ls_log-type    = ls_return-type.
  ls_log-msgid   = ls_return-id.
  ls_log-msgnr   = ls_return-number.
  ls_log-message = lv_msg.
  APPEND ls_log TO lt_log.

  IF ls_return-type CA 'EA'.
    lv_has_error = abap_true.
  ENDIF.

ENDLOOP.

IF lv_has_error = abap_true.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ELSE.
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
    EXPORTING wait = 'X'.
ENDIF.

* ★ 시나리오 2 — BDC 호출 + 메시지 처리
" ... BDC 데이터 빌드 ...

CALL TRANSACTION 'MM02'
  USING    lt_bdcdata
  MODE     'N'                  " N = 화면 비표시
  UPDATE   'S'                  " S = 동기
  MESSAGES INTO lt_msgcol.      " ★ 필수

CLEAR: lt_log, lv_has_error.

LOOP AT lt_msgcol INTO ls_msgcol.

  MESSAGE ID     ls_msgcol-msgid
          TYPE   ls_msgcol-msgtyp
          NUMBER ls_msgcol-msgnr
          WITH   ls_msgcol-msgv1
                 ls_msgcol-msgv2
                 ls_msgcol-msgv3
                 ls_msgcol-msgv4
          INTO   lv_msg.

  ls_log-type    = ls_msgcol-msgtyp.
  ls_log-msgid   = ls_msgcol-msgid.
  ls_log-msgnr   = ls_msgcol-msgnr.
  ls_log-message = lv_msg.
  APPEND ls_log TO lt_log.

  IF ls_msgcol-msgtyp CA 'EA'.
    lv_has_error = abap_true.
  ENDIF.

ENDLOOP.

* ★ 로그 출력
LOOP AT lt_log INTO ls_log.
  WRITE: / ls_log-type, ls_log-msgid, ls_log-msgnr, ls_log-message.
ENDLOOP.

같이 보면 좋은 글: "BAdI 찾는 방법 5가지 — CL_EXITHANDLER 디버깅·SE84·SXS_ATTR 메타테이블" — 메시지가 사용자 BAdI 에서 발생할 때 어디서 호출되는지 추적하는 방법까지 함께 알아두면 디버깅이 훨씬 빨라집니다.


요약

방법 하는 일 권장 시나리오
1 MESSAGE ... INTO 구문 표준 ABAP 방식 (가장 권장)
2 FORMAT_MESSAGE FM 레거시 호환 / 다국어 강제 지정 시
3 BAPIRET2-MESSAGE 그대로 필드가 채워진 BAPI 만 (위험)
4 Message 브레이크포인트 에러 발생 위치 추적 / 원인 분석

BAPI / BDC 의 에러 메시지 처리는 "메시지 ID + 번호 + 변수 4개" 패턴 만 정확히 이해하면 두 메커니즘이 동일한 방식으로 처리됩니다. MESSAGE ... INTO 구문을 기본으로 잡고, 로그에는 TYPE·ID·NUMBER·빌드된 텍스트를 함께 적재해두면 운영 중 에러 발생 시 즉시 원인 추적이 가능합니다. 표준 / 사내 BAdI 가 어디서 메시지를 던지는지 모를 때는 디버거의 Message Breakpoint 가 가장 빠른 진단 도구입니다.


Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.

BAPIRET2 / BDCMSGCOLL 구조 · FORMAT_MESSAGE Function Module 시그니처 · T100 메시지 마스터 동작은 SAP NetWeaver 표준(ECC 6.0 / S/4HANA on-premise) 기준이며, 사내 BAPI / BAdI 커스터마이징에 따라 RETURN 필드 채움 정책이 다를 수 있으니 운영 시스템 적용 전 개발·QA 환경에서 검증하시기 바랍니다.