vxcontrol/pentagi · error
failed to copy resource %q: %w
Error message
failed to copy resource %q: %w
What it means
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.
Source
Thrown at backend/pkg/server/services/resources.go:1653
if err := tx.Delete(&dest).Error; err != nil {
return result, fmt.Errorf("failed to delete destination for overwrite: %w", err)
}
result.Deleted = append(result.Deleted, convertResource(dest))
if dest.Hash != "" {
result.OrphanHashes = append(result.OrphanHashes, dest.Hash)
}
}
newRec := models.UserResource{
UserID: uid,
Hash: e.Hash,
Name: path.Base(newPath),
Path: newPath,
Size: e.Size,
IsDir: e.IsDir,
}
if err := tx.Create(&newRec).Error; err != nil {
return result, fmt.Errorf("failed to copy resource %q: %w", e.Path, err)
}
entry := convertResource(newRec)
if _, wasExisting := existingSet[newPath]; wasExisting {
result.Updated = append(result.Updated, entry)
} else {
result.Added = append(result.Added, entry)
}
}
return result, nil
}
// ---- DELETE /resources/ ----------------------------------------------------
// DeleteResource deletes one or more files or directories (recursively) by virtual path.
// @Summary Delete a resource (file or directory)
// @Tags Resources
// @Produce jsonView on GitHub (pinned to ea665308ba)
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
Example fix
// before copyDir(uid, src, dst, false) // may 500 with 'failed to copy resource "x": duplicate key' // after copyDir(uid, src, dst, true) // allow overwrite of concurrently created paths
Defensive patterns
Strategy: retry
Validate before calling
// pre-check all destination paths before bulk copy
newPaths := computeNewPaths(srcTree, srcPath, dstPath)
existing, err := findResourcesByPaths(uid, newPaths)
if err != nil { return err }
if len(existing) > 0 && !force { return errConflict } Try / catch
if err := copyDir(uid, src, dst, force); err != nil {
var qerr *quotedPathErr
if errors.As(err, &qerr) {
log.Errorf("copy failed for %s: %v", qerr.path, qerr.cause)
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Racing copy/move operations on the same destination tree; paths exceeding varchar length after prefix replacement; transient DB outage mid-copy.
Related errors
- failed to move resource %q: %w
- failed to copy resource: %w
- failed to check destination conflicts: %w
- failed to create resource directory %q: %w
- failed to fetch resources: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/67e91bf1b91be44e.
Report an issue: GitHub.