{"record":{"id":"6024ece454960e6a","repo":"bagisto/bagisto","slug":"product-app-datagrid-variant-already-exist-messag","errorCode":null,"errorMessage":"product::app.datagrid.variant-already-exist-message","messagePattern":"product::app\\.datagrid\\.variant-already-exist-message","errorType":"exception","errorClass":"\\Exception","httpStatus":null,"severity":"error","filePath":"packages/Webkul/Product/src/Repositories/ProductRepository.php","lineNumber":113,"sourceCode":"\n    /**\n     * Copy product.\n     *\n     * @param  int  $id\n     * @return Product\n     */\n    public function copy($id)\n    {\n        $product = $this->with([\n            'attribute_family',\n            'categories',\n            'customer_group_prices',\n            'inventories',\n            'inventory_sources',\n        ])->findOrFail($id);\n\n        if ($product->parent_id) {\n            throw new \\Exception(trans('product::app.datagrid.variant-already-exist-message'));\n        }\n\n        return DB::transaction(function () use ($product) {\n            $copiedProduct = $product->getTypeInstance()->copy();\n\n            return $copiedProduct;\n        });\n    }\n\n    /**\n     * Copy product.\n     */\n    public function setSearchEngine(string $searchEngine): self\n    {\n        $this->searchEngine = $searchEngine;\n\n        return $this;\n    }","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/bagisto/bagisto/blob/326bc45f17cd66d2835a934d21c264d3ee12d935/packages/Webkul/Product/src/Repositories/ProductRepository.php#L95-L131","documentation":"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.","triggerScenarios":"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.","commonSituations":"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","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"],"exampleFix":"// before - copying every selected row, dies on variants\nforeach ($request->input('indices') as $id) {\n    $this->productRepository->copy($id);\n}\n\n// after - skip variants, copy their parents instead\nforeach ($request->input('indices') as $id) {\n    $product = $this->productRepository->findOrFail($id);\n    $this->productRepository->copy($product->parent_id ?? $product->id);\n}","handlingStrategy":"validation","validationCode":"$product = $this->productRepository->findOrFail($id);\n\nif ($product->parent_id) {\n    // copy the parent configurable instead; never copy a variant standalone\n    $id = $product->parent_id;\n}\n$this->productRepository->copy($id);","typeGuard":"function isProductVariant($product): bool\n{\n    return ! is_null($product?->parent_id);\n}","tryCatchPattern":"try {\n    $this->productRepository->copy($id);\n} catch (\\Exception $e) {\n    return response()->json(['error' => $e->getMessage()], 422);\n}","preventionTips":["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"],"tags":["bagisto","product","variant","copy","admin"],"backgroundTag":"cannot-copy-product-variant","analyzedSha":"326bc45f17cd66d2835a934d21c264d3ee12d935","analyzedAt":"2026-08-17T00:51:54.202Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}