cloudreve/cloudreve · error
failed to copy file: %w
Error message
failed to copy file: %w
What it means
Thrown by File.Copy when saving one of the new file rows fails (stm.Save(ctx)). Copy inserts clones of the source files into destination folders; the most common concrete cause is a unique-constraint violation on (parent, owner, name) when a file with the same name already exists at the destination.
Source
Thrown at inventory/file.go:643
if file.PrimaryEntity > 0 {
stm.SetPrimaryEntity(file.PrimaryEntity)
}
if file.Props != nil && dstMap[file.FileChildren][0].OwnerID == file.OwnerID {
stm.SetProps(file.Props)
}
return stm
})
metadataStm := []*ent.MetadataCreate{}
entityStm := []*ent.EntityUpdate{}
newDstMap := make(map[int][]*ent.File, len(files))
sizeDiff := int64(0)
for index, stm := range copyFileStm {
newFile, err := stm.Save(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to copy file: %w", err)
}
fileMetadata, err := files[index].Edges.MetadataOrErr()
if err != nil {
return nil, nil, fmt.Errorf("failed to get metadata of file: %w", err)
}
metadataStm = append(metadataStm, lo.FilterMap(fileMetadata, func(metadata *ent.Metadata, index int) (*ent.MetadataCreate, bool) {
if lo.Contains(args.ExcludedMetadataKeys, metadata.Name) {
return nil, false
}
return f.client.Metadata.Create().
SetName(metadata.Name).
SetValue(metadata.Value).
SetFile(newFile).
SetIsPublic(metadata.IsPublic), true
})...)
View on GitHub (pinned to 20c95ad73f)
Solutions
- Check for name collisions in the destination before copying, or implement rename-on-conflict (append suffix)
- Unwrap to confirm whether it is a duplicate-key error vs driver failure
- Pre-download/validate source rows against the current schema before copying
- Retry only for transient driver causes, not for unique violations
Example fix
// before
newFiles, diff, err := inv.Copy(ctx, &inventory.CopyParameter{Files: files, DstMap: dst})
// after
// resolve name conflicts first
for _, f := range files {
if exists, _ := inv.IsNameAvailable(ctx, dstOwner, dstParent, f.Name); !exists {
f.Name = uniquify(f.Name)
}
}
newFiles, diff, err := inv.Copy(ctx, &inventory.CopyParameter{Files: files, DstMap: dst}) Defensive patterns
Strategy: validation
Validate before calling
// pre-check destination name availability
for _, f := range files {
if taken, _ := inv.IsChildExist(ctx, dstParent, dstOwner, f.Name); taken {
return fmt.Errorf("destination already has %q; rename first", f.Name)
}
} Try / catch
if _, _, err := inv.Copy(ctx, params); err != nil {
var mysqlErr *mysql.MySQLError
if errors.As(err, &mysqlErr) && mysqlErr.Number == 1062 {
return fmt.Errorf("name conflict at destination: %w", err)
}
return err
} Prevention
- Resolve name conflicts before Copy (rename or merge policy)
- Lock or queue copies sharing a source file
- Don't blind-retry unique-violation failures
When it happens
Trigger: Copying into a folder that already contains a file with the identical name; connection/driver failure; a NOT NULL field left unset because source rows predate a schema change; context cancelled mid-loop.
Common situations: Web UI copy without rename policy collides with existing destination file; two concurrent copies of the same source into the same folder race the uniqueness check; copying legacy rows missing fields required by newer ent codegen.
Related errors
- failed to copy entity: %w
- failed to create group %q: %w
- failed to create setting %q: %w
- failed to copy metadata: %w
- failed creating schema resources: %w
AI-assisted analysis of cloudreve/cloudreve@20c95ad73f (2026-08-16).
Data as JSON: /api/errors/782d5ce817d8f56a.
Report an issue: GitHub.