{"record":{"id":"67e91bf1b91be44e","repo":"vxcontrol/pentagi","slug":"failed-to-copy-resource-q-w","errorCode":null,"errorMessage":"failed to copy resource %q: %w","messagePattern":"failed to copy resource %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/server/services/resources.go","lineNumber":1653,"sourceCode":"\t\t\tif err := tx.Delete(&dest).Error; err != nil {\n\t\t\t\treturn result, fmt.Errorf(\"failed to delete destination for overwrite: %w\", err)\n\t\t\t}\n\t\t\tresult.Deleted = append(result.Deleted, convertResource(dest))\n\t\t\tif dest.Hash != \"\" {\n\t\t\t\tresult.OrphanHashes = append(result.OrphanHashes, dest.Hash)\n\t\t\t}\n\t\t}\n\n\t\tnewRec := models.UserResource{\n\t\t\tUserID: uid,\n\t\t\tHash:   e.Hash,\n\t\t\tName:   path.Base(newPath),\n\t\t\tPath:   newPath,\n\t\t\tSize:   e.Size,\n\t\t\tIsDir:  e.IsDir,\n\t\t}\n\t\tif err := tx.Create(&newRec).Error; err != nil {\n\t\t\treturn result, fmt.Errorf(\"failed to copy resource %q: %w\", e.Path, err)\n\t\t}\n\t\tentry := convertResource(newRec)\n\t\tif _, wasExisting := existingSet[newPath]; wasExisting {\n\t\t\tresult.Updated = append(result.Updated, entry)\n\t\t} else {\n\t\t\tresult.Added = append(result.Added, entry)\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\n// ---- DELETE /resources/ ----------------------------------------------------\n\n// DeleteResource deletes one or more files or directories (recursively) by virtual path.\n// @Summary Delete a resource (file or directory)\n// @Tags Resources\n// @Produce json","sourceCodeStart":1635,"sourceCodeEnd":1671,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/services/resources.go#L1635-L1671","documentation":"copyDirResource inserts one new UserResource row per source entry when copying a directory tree. This error identifies WHICH source file failed to copy (its path is quoted) by wrapping the GORM Create error, and aborts the transaction.","triggerScenarios":"tx.Create fails for a specific entry: unique (user_id, path) violation from a concurrent writer that created the same path after the conflict check, column length exceeded by a deep newPath, or DB failure.","commonSituations":"Racing copy/move operations on the same destination tree; paths exceeding varchar length after prefix replacement; transient DB outage mid-copy.","solutions":["Retry; if unique-violation, the path was created concurrently — re-run with force=true or pick a new destination","Check column sizes for path/name against the longest produced path","Inspect the wrapped driver error to distinguish constraint vs connectivity","Serialize bulk copy operations per user to avoid races"],"exampleFix":"// before\ncopyDir(uid, src, dst, false) // may 500 with 'failed to copy resource \"x\": duplicate key'\n// after\ncopyDir(uid, src, dst, true) // allow overwrite of concurrently created paths","handlingStrategy":"retry","validationCode":"// pre-check all destination paths before bulk copy\nnewPaths := computeNewPaths(srcTree, srcPath, dstPath)\nexisting, err := findResourcesByPaths(uid, newPaths)\nif err != nil { return err }\nif len(existing) > 0 && !force { return errConflict }","typeGuard":null,"tryCatchPattern":"if err := copyDir(uid, src, dst, force); err != nil {\n    var qerr *quotedPathErr\n    if errors.As(err, &qerr) {\n        log.Errorf(\"copy failed for %s: %v\", qerr.path, qerr.cause)\n    }\n    return err\n}","preventionTips":["Pre-compute and check destination paths before large copies","Use force=true when overwrite-by-race is acceptable","Keep path lengths within DB limits after prefix replacement","Serialize bulk directory copies per user"],"tags":["gorm","database","copy","unique-constraint"],"backgroundTag":"database-insert-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}