ITAB_DUPLICATE_KEY¶
A duplicate key was found when copying data into a sorted or hashed internal table with UNIQUE KEY.
ABAP found a duplicate key entry while populating a SORTED TABLE WITH UNIQUE KEY or HASHED TABLE WITH UNIQUE KEY from a mass operation such as a direct table assignment or a SELECT INTO TABLE.
Symptom¶
ST22 shows:
Runtime Errors ITAB_DUPLICATE_KEY
Exception CX_SY_ITAB_DUPLICATE_KEY
Short text Table has unique key: duplicate values not allowed.
The dump line is typically a mass assignment (lt_hashed = lt_source) or a SELECT INTO TABLE.
This dump cannot be caught with TRY/CATCH
Although ST22 lists CX_SY_ITAB_DUPLICATE_KEY, this dump fires as a kernel-level operation during mass assignments. TRY/CATCH does not intercept it. The only solution is to prevent the duplicate before the assignment — see the fixes below.
Cause¶
| Trigger | Behaviour |
|---|---|
lt_hashed = lt_standard — mass assignment, source has duplicates |
Dumps |
SELECT * FROM t INTO TABLE lt_hashed — DB result has duplicate keys |
Dumps |
INSERT VALUE #(...) INTO TABLE lt_hashed — single row, key already exists |
Does NOT dump — sets sy-subrc = 4 silently (ABAP 7.40+) |
Single INSERT does not dump on modern ABAP
From ABAP 7.40 onwards, INSERT INTO TABLE on a UNIQUE KEY table with a duplicate key sets sy-subrc = 4 and skips the insert — no dump, no exception. The dump only fires during mass operations.
Reproduce¶
REPORT z_itab_duplicate_key.
START-OF-SELECTION.
TYPES: BEGIN OF ty_item,
matnr TYPE matnr,
qty TYPE i,
END OF ty_item.
DATA: lt_source TYPE STANDARD TABLE OF ty_item WITH DEFAULT KEY,
lt_hashed TYPE HASHED TABLE OF ty_item WITH UNIQUE KEY matnr.
" Build source table with a duplicate key
APPEND VALUE #( matnr = 'MAT001' qty = 10 ) TO lt_source.
APPEND VALUE #( matnr = 'MAT001' qty = 20 ) TO lt_source. " same key — duplicate
" Mass assignment to UNIQUE KEY table → ITAB_DUPLICATE_KEY dump
lt_hashed = lt_source.
Fix¶
Sort and deduplicate the source table before the mass assignment. This is the safest and most common fix.
REPORT z_itab_dup_fix1.
START-OF-SELECTION.
TYPES: BEGIN OF ty_item,
matnr TYPE matnr,
qty TYPE i,
END OF ty_item.
DATA: lt_source TYPE STANDARD TABLE OF ty_item WITH DEFAULT KEY,
lt_hashed TYPE HASHED TABLE OF ty_item WITH UNIQUE KEY matnr.
APPEND VALUE #( matnr = 'MAT001' qty = 10 ) TO lt_source.
APPEND VALUE #( matnr = 'MAT001' qty = 20 ) TO lt_source.
" Sort and deduplicate BEFORE copying to the hashed table
SORT lt_source BY matnr.
DELETE ADJACENT DUPLICATES FROM lt_source COMPARING matnr.
" Now safe — no duplicates in lt_source
lt_hashed = lt_source.
WRITE: / 'Rows in hashed table:', lines( lt_hashed ). " 1
On modern ABAP, a single INSERT INTO TABLE sets sy-subrc = 4 on a duplicate without dumping. Use that to fall back to MODIFY TABLE (which updates the existing row).
REPORT z_itab_dup_fix2.
START-OF-SELECTION.
TYPES: BEGIN OF ty_item,
matnr TYPE matnr,
qty TYPE i,
END OF ty_item.
DATA: lt_hashed TYPE HASHED TABLE OF ty_item WITH UNIQUE KEY matnr,
ls_item TYPE ty_item.
" First row — inserts cleanly
ls_item-matnr = 'MAT001'.
ls_item-qty = 10.
INSERT ls_item INTO TABLE lt_hashed.
" Second row — same key, would normally dump on mass ops
" but single INSERT just sets sy-subrc = 4 on modern ABAP
ls_item-matnr = 'MAT001'.
ls_item-qty = 20.
INSERT ls_item INTO TABLE lt_hashed.
IF sy-subrc = 4.
" Key already exists — update the existing row
MODIFY TABLE lt_hashed FROM ls_item.
ENDIF.
WRITE: / 'qty:', lt_hashed[ matnr = 'MAT001' ]-qty. " 20
When loading from a database, use DISTINCT so the result can never contain duplicate key values. The local type must match exactly the fields being selected.
REPORT z_itab_dup_fix3.
START-OF-SELECTION.
" marc has one row per material+plant, so matnr repeats across plants.
" We want a unique list of material numbers → DISTINCT + narrow type.
TYPES: BEGIN OF ty_matnr,
matnr TYPE marc-matnr,
END OF ty_matnr.
DATA lt_unique TYPE HASHED TABLE OF ty_matnr WITH UNIQUE KEY matnr.
SELECT DISTINCT matnr
FROM marc
INTO TABLE @lt_unique
UP TO 100 ROWS.
WRITE: / 'Unique materials:', lines( lt_unique ).
If duplicates are normal for your data, use a STANDARD TABLE — it never enforces key uniqueness.
REPORT z_itab_dup_fix4.
START-OF-SELECTION.
TYPES: BEGIN OF ty_item,
matnr TYPE matnr,
qty TYPE i,
END OF ty_item.
" STANDARD TABLE accepts duplicate keys — no dump, no sy-subrc issue
DATA lt_items TYPE STANDARD TABLE OF ty_item WITH DEFAULT KEY.
APPEND VALUE #( matnr = 'MAT001' qty = 10 ) TO lt_items.
APPEND VALUE #( matnr = 'MAT001' qty = 20 ) TO lt_items.
WRITE: / 'Rows:', lines( lt_items ). " 2
MODIFY TABLE replaces the entire row
MODIFY TABLE lt_hashed FROM ls_item replaces all non-key fields with the values in ls_item. If you only want to update one field, read the row first (READ TABLE ... INTO ls_row), update that field, then MODIFY TABLE ... FROM ls_row.
Prevention¶
- Before copying a standard table into a UNIQUE KEY table, always
SORT+DELETE ADJACENT DUPLICATESfirst. - Use
DISTINCTorGROUP BYin SELECT statements that feed into UNIQUE KEY tables. - For single-row operations, use
INSERT+IF sy-subrc = 4 → MODIFY TABLEinstead of assuming the key is unique. - Do not rely on
TRY/CATCH cx_sy_itab_duplicate_key— this dump fires at kernel level and cannot be caught.
See also¶
GETWA_NOT_ASSIGNED— related internal table access dump- Transaction ST22 — ABAP runtime error analysis