Skip to content

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 DUPLICATES first.
  • Use DISTINCT or GROUP BY in SELECT statements that feed into UNIQUE KEY tables.
  • For single-row operations, use INSERT + IF sy-subrc = 4 → MODIFY TABLE instead 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

Comments