magento2: Attribute option(with numeric value) cannot be added in case option with same option_id already exists

Preconditions (*)

  1. Reproducible on Magento versions 2.4.1, 2.4.2
  2. Issue was found during importing products but also is reproducible in Admin on product attribute page. Attribute option(with numeric value) cannot be added in case option with same option_id already exists.

OptionManagement->add() methods call for AbstractSource->getOptionId() to find out if given option already exists for given attribute. As getOptionId param add() sends option label. Problem is that getOptionId() checks for both label and option_id (value). So if label is a numerical string and option with same id (but different label) exists, exception is thrown.

Model/Entity/Attribute/OptionManagement

public function add($entityType, $attributeCode, $option)
{
    $attribute = $this->loadAttribute($entityType, (string)$attributeCode);

    $label = trim($option->getLabel() ?: '');
    if (empty($label)) {
        throw new InputException(__('The attribute option label is empty. Enter the value and try again.'));
    }

    if ($attribute->getSource()->getOptionId($label) !== null) {
        throw new InputException(
            __(
                'Admin store attribute option label "%1" is already exists.',
                $option->getLabel()
            )
        );
    }

Model/Entity/Attribute/Source/AbstractSource

public function getOptionId($value)
    {
        foreach ($this->getAllOptions() as $option) {
            if ($this->mbStrcasecmp($option['label'], $value) == 0 || $option['value'] == $value) {
                return $option['value'];
            }
        }
        return null;
    }

Steps to reproduce (*)

1 Go to Admin > Stores > Attributes[Product]. 1.1 Create or open any multiselect attribute. 1.2 Add new option and save attribute 1.3 Add one more option with value of first option id and save attribute Screenshot 2021-05-26 at 12 32 20 2 Second option(import): In CSV import products file add new product with select/multiselect attribute with value of existing option_id in eav_attribute_option_value table(eg. in scv file attribute with value: 10,180. In eav_attribute_option_value must exist option with option_id = 10 or 180). Import product by using command: bin/magento integration:job:run transport_product_import_std_csv

Expected result (*)

new attribute option will be successfully added Screenshot 2021-05-26 at 12 43 40

Actual result (*)

Error msg in case of import: Exception: Admin store attribute option label “180” is already exists.

Error msg in admin while saving new attribute option: The value of Admin must be unique.(180)


Please provide Severity assessment for the Issue as Reporter. This information will help during Confirmation and Issue triage processes.

  • Severity: S0 - Affects critical data or functionality and leaves users without workaround.
  • Severity: S1 - Affects critical data or functionality and forces users to employ a workaround.
  • Severity: S2 - Affects non-critical data or functionality and forces users to employ a workaround.
  • Severity: S3 - Affects non-critical data or functionality and does not force users to employ a workaround.
  • Severity: S4 - Affects aesthetics, professional look and feel, “quality” or “usability”.

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 3
  • Comments: 26 (10 by maintainers)

Most upvoted comments

Confirming this is an valid issue I just ran across on 2.4.2-p1

Can also confirm the patch provided in https://github.com/magento/magento2/issues/33073#issuecomment-848631459 fixes the issue for me.

Thanks @aleksandrvaimo 😃

Patch for fixing this issue:

Fix: Check if attribute exists with numeric option value

Issue was found during product import. Also is reproducible in Admin on product attribute page.

Before adding the attribute option \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource::getOptionId() searches for attribute value by value and label at the same time, so in case label exists error will be thrown.

@steps

  1. Go to Admin > Stores > Attributes[Product]. Create or open any multiselect attribute and try to save attribute with same value as already existing option_id of any other attribute

@expected

  1. new attribute option should be added

@actual

  1. thrown error message: Admin store attribute option label “%1” is already exists.

@link https://github.com/magento/magento2/issues/33073 @package magento/module-eav @version >=102.1.0

--- Model/Entity/Attribute/Source/AbstractSource.php.org
+++ Model/Entity/Attribute/Source/AbstractSource.php
@@ -95,7 +95,23 @@
         }
         return null;
     }
-
+    //PATCH fix-incorrectly-checked-attribute-option-number-value
+    /**
+     * Get option id by label.
+     *
+     * @param string $value
+     * @return null|string
+     */
+    public function getOptionIdByLabel($value)
+    {
+        foreach ($this->getAllOptions() as $option) {
+            if ($this->mbStrcasecmp($option['label'], $value) === 0) {
+                return $option['value'];
+            }
+        }
+        return null;
+    }
+    //~PATCH
     /**
      * Add Value Sort To Collection Select
      *
--- Model/Entity/Attribute/OptionManagement.php.org
+++ Model/Entity/Attribute/OptionManagement.php
@@ -60,12 +60,16 @@
     {
         $attribute = $this->loadAttribute($entityType, (string)$attributeCode);

+        //PATCH fix-incorrectly-checked-attribute-option-number-value
         $label = trim($option->getLabel() ?: '');
-        if (empty($label)) {
+        //~PATCH
+        if ($label === null || $label === '') {
             throw new InputException(__('The attribute option label is empty. Enter the value and try again.'));
         }

-        if ($attribute->getSource()->getOptionId($label) !== null) {
+        //PATCH
+        if ($attribute->getSource()->getOptionIdByLabel($label) !== null) {
+        //~PATCH
             throw new InputException(
                 __(
                     'Admin store attribute option label "%1" is already exists.',