{"record":{"id":"ea7ed12eaec560a1","repo":"vxcontrol/pentagi","slug":"failed-to-copy-resource-w","errorCode":null,"errorMessage":"failed to copy resource: %w","messagePattern":"failed to copy resource: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/server/services/resources.go","lineNumber":1544,"sourceCode":"\t\tif err := tx.Delete(&dest).Error; err != nil {\n\t\t\treturn result, fmt.Errorf(\"failed to delete destination for overwrite: %w\", err)\n\t\t}\n\t\tresult.Deleted = append(result.Deleted, convertResource(dest))\n\t\tif dest.Hash != \"\" {\n\t\t\tresult.OrphanHashes = append(result.OrphanHashes, dest.Hash)\n\t\t}\n\t}\n\n\tnewRec := models.UserResource{\n\t\tUserID: uid,\n\t\tHash:   src.Hash,\n\t\tName:   path.Base(targetPath),\n\t\tPath:   targetPath,\n\t\tSize:   src.Size,\n\t\tIsDir:  false,\n\t}\n\tif err := tx.Create(&newRec).Error; err != nil {\n\t\treturn result, fmt.Errorf(\"failed to copy resource: %w\", err)\n\t}\n\n\tentry := convertResource(newRec)\n\tif exists {\n\t\tresult.Updated = append(result.Updated, entry)\n\t} else {\n\t\tresult.Added = append(result.Added, entry)\n\t}\n\treturn result, nil\n}\n\nfunc (s *ResourceService) copyDirResource(\n\ttx *gorm.DB,\n\tuid uint64,\n\tsrcPath, dstPath string,\n\tforce bool,\n) (copyResourceResult, error) {\n\tresult := copyResourceResult{}","sourceCodeStart":1526,"sourceCodeEnd":1562,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/services/resources.go#L1526-L1562","documentation":"copyFileResource inserts the new UserResource row for the copied file inside the copy transaction. This error wraps the GORM/Postgres failure of that INSERT, meaning the database rejected the copy record (not the file itself). The whole copy transaction is rolled back by the caller.","triggerScenarios":"DELETE/constraint failure on tx.Create while copying a file: e.g. a unique (user_id, path) collision from a concurrent writer, a NOT NULL/length violation on path or name, or a dead/broken DB connection during the copy API call.","commonSituations":"Two copy/move requests racing to create the same destination path without force; path exceeding the DB column length after a deep destination directory; DB connection dropped mid-request.","solutions":["Retry the request; if it is a conflict, list the destination first and either pick a new destination path or pass force=true","Check the DB schema/migrations for the user_resources unique index and column sizes","Verify DB connectivity/health (logs will show the wrapped %w cause)","If caused by concurrent writes, serialize copy operations per user or add retry-on-serialization logic"],"exampleFix":"// before\nres, err := svc.CopyResource(uid, src, dst, false)\n// after\nif _, exists := checkDestExists(uid, dst); exists && !allowOverwrite {\n    return errors.New(\"destination exists; pass force to overwrite\")\n}\nres, err := svc.CopyResource(uid, src, dst, allowOverwrite)","handlingStrategy":"retry","validationCode":"exists, err := resourceExists(uid, dstPath)\nif err != nil { return err }\nif exists && !force { return errConflict }","typeGuard":null,"tryCatchPattern":"res, err := svc.CopyResource(uid, src, dst, force)\nif err != nil {\n    var conflict error\n    if errors.As(err, &conflict) && errors.Is(conflict, errResourceConflict) {\n        // handle overwrite policy\n    } else {\n        log.WithError(err).Error(\"copy failed (db insert)\") // inspect %w cause\n    }\n}","preventionTips":["Check destination existence before copying, or pass force deliberately","Avoid concurrent writers to the same path subtree","Keep paths within DB column length limits","Monitor DB health; wrap inserts with bounded retries for transient errors"],"tags":["gorm","database","copy","resources"],"backgroundTag":"database-insert-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}