bagisto/bagisto · error · \Exception

product::app.datagrid.variant-already-exist-message

Error message

product::app.datagrid.variant-already-exist-message

What it means

ProductRepository::copy() refuses to copy a product that is itself a variant (parent_id set) - the message key literally says variant-already-exist-message. A variant only exists in the context of its configurable parent, so a standalone copy would be an orphan; copying the parent configurable product copies its variants via Configurable::copyRelationships instead.

Source

Thrown at packages/Webkul/Product/src/Repositories/ProductRepository.php:113

    /**
     * Copy product.
     *
     * @param  int  $id
     * @return Product
     */
    public function copy($id)
    {
        $product = $this->with([
            'attribute_family',
            'categories',
            'customer_group_prices',
            'inventories',
            'inventory_sources',
        ])->findOrFail($id);

        if ($product->parent_id) {
            throw new \Exception(trans('product::app.datagrid.variant-already-exist-message'));
        }

        return DB::transaction(function () use ($product) {
            $copiedProduct = $product->getTypeInstance()->copy();

            return $copiedProduct;
        });
    }

    /**
     * Copy product.
     */
    public function setSearchEngine(string $searchEngine): self
    {
        $this->searchEngine = $searchEngine;

        return $this;
    }

View on GitHub (pinned to 326bc45f17)

Solutions

  1. Copy the parent configurable product instead - its variants are duplicated with it
  2. If you need a similar standalone product, create a new simple product rather than copying the variant
  3. Hide the copy action for products where parent_id is set

Example fix

// before - copying every selected row, dies on variants
foreach ($request->input('indices') as $id) {
    $this->productRepository->copy($id);
}

// after - skip variants, copy their parents instead
foreach ($request->input('indices') as $id) {
    $product = $this->productRepository->findOrFail($id);
    $this->productRepository->copy($product->parent_id ?? $product->id);
}
Defensive patterns

Strategy: validation

Validate before calling

$product = $this->productRepository->findOrFail($id);

if ($product->parent_id) {
    // copy the parent configurable instead; never copy a variant standalone
    $id = $product->parent_id;
}
$this->productRepository->copy($id);

Type guard

function isProductVariant($product): bool
{
    return ! is_null($product?->parent_id);
}

Try / catch

try {
    $this->productRepository->copy($id);
} catch (\Exception $e) {
    return response()->json(['error' => $e->getMessage()], 422);
}

Prevention

When it happens

Trigger: Admin product grid 'Copy' action (or programmatic call to the product copy endpoint) with the ID of a simple product that is a variant of a configurable; DataGrid row action exposed for variant rows.

Common situations: Admin UI customization that shows the copy action on every row; scripts enumerating all products and calling copy(); browsing a variant through a flattened product grid

Related errors


AI-assisted analysis of bagisto/bagisto@326bc45f17 (2026-08-17). Data as JSON: /api/errors/6024ece454960e6a. Report an issue: GitHub.