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
- Copy the parent configurable product instead - its variants are duplicated with it
- If you need a similar standalone product, create a new simple product rather than copying the variant
- 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
- Hide the copy action for variant rows in DataGrids
- In bulk scripts, resolve to the parent before calling copy
- Treat parent_id as the variant marker whenever handling product copies
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
- product::app.response.product-can-not-be-copied
- admin::app.sales.refunds.create.invalid-qty
- admin::app.sales.refunds.create.invalid-qty
- admin::app.settings.themes.edit.slider-required
- product::app.checkout.cart.inventory-warning
AI-assisted analysis of bagisto/bagisto@326bc45f17 (2026-08-17).
Data as JSON: /api/errors/6024ece454960e6a.
Report an issue: GitHub.