{"record":{"id":"904c8802b674e04a","repo":"cloudreve/cloudreve","slug":"failed-to-delete-files-v-w","errorCode":null,"errorMessage":"failed to delete files %v: %w","messagePattern":"failed to delete files (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"inventory/file.go","lineNumber":601,"sourceCode":"\t)\n\n\tfor i, group := range fileGroups {\n\t\t// 4. Delete shares/metadata/directlinks if needed;\n\t\tif _, err := f.client.Share.Delete().Where(share.HasFileWith(group)).Exec(ctx); err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to delete shares of files %v: %w\", group, err)\n\t\t}\n\n\t\tif _, err := f.client.Metadata.Delete().Where(metadata.FileIDIn(chunks[i]...)).Exec(schema.SkipSoftDelete(ctx)); err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to delete metadata of files %v: %w\", group, err)\n\t\t}\n\n\t\tif _, err := f.client.DirectLink.Delete().Where(directlink.FileIDIn(chunks[i]...)).Exec(hardDeleteCtx); err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to delete direct links of files %v: %w\", group, err)\n\t\t}\n\n\t\t// 5. Delete files.\n\t\tif _, err := f.client.File.Delete().Where(group).Exec(hardDeleteCtx); err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to delete files %v: %w\", group, err)\n\t\t}\n\t}\n\n\treturn toBeRecycled, storageReduced, nil\n}\n\nfunc (f *fileClient) Copy(ctx context.Context, args *CopyParameter) (map[int][]*ent.File, StorageDiff, error) {\n\tfiles := args.Files\n\tdstMap := args.DstMap\n\tpageSize := capPageSize(f.maxSQlParam, intsets.MaxInt, 10)\n\t// 1. Copy files and metadata\n\tcopyFileStm := lo.Map(files, func(file *ent.File, index int) *ent.FileCreate {\n\n\t\tstm := f.client.File.Create().\n\t\t\tSetName(file.Name).\n\t\t\tSetOwnerID(dstMap[file.FileChildren][0].OwnerID).\n\t\t\tSetSize(file.Size).\n\t\t\tSetType(file.Type).","sourceCodeStart":583,"sourceCodeEnd":619,"githubUrl":"https://github.com/cloudreve/cloudreve/blob/20c95ad73f3a8bcb72887fea91ff31ab24fa1011/inventory/file.go#L583-L619","documentation":"Final sub-step of File.Delete (step 5): the file rows themselves are physically deleted (File.Delete().Where(group) under SkipSoftDelete). This error means the terminal DELETE failed after shares/metadata/directlinks were already removed for this group — a partially progressed cascade.","triggerScenarios":"FK RESTRICT from a table still referencing files (file_entities join rows, child files with parent FK if a child outside the group references a deleted parent); deadlock; connection loss. Also fires if the ent schema's edge ON DELETE behavior was changed without migration.","commonSituations":"Deleting a parent folder batch while a child file outside the batch still references it (broken batching); concurrent upload creating rows referencing the file; customized schema FKs.","solutions":["Unwrap to see the exact FK name and which table still references files","Ensure all descendants are included in the same Delete call (folder deletes must collect the full subtree)","Re-run the operation: already-removed dependent rows make the retry proceed further","Retry on deadlock-class causes"],"exampleFix":"// before\ninv.Delete(ctx, topLevelFiles, props)\n\n// after\nall := collectSubtree(ctx, topLevelFiles) // include every descendant\ninv.Delete(ctx, all, props)","handlingStrategy":"try-catch","validationCode":"// include the whole subtree so no child references a deleted parent\nall := append([]*ent.File{}, files...)\nall = append(all, collectDescendants(ctx, files)...)\nif len(all) == 0 { return nil }","typeGuard":null,"tryCatchPattern":"if _, _, err := inv.Delete(ctx, all, props); err != nil {\n    var mysqlErr *mysql.MySQLError\n    if errors.As(err, &mysqlErr) && mysqlErr.Number == 1451 {\n        return fmt.Errorf(\"file still referenced (child or join row outside batch): %w\", err)\n    }\n    if isDeadlock(err) { _, _, err = inv.Delete(ctx, all, props) }\n    return err\n}","preventionTips":["Always delete folders as full collected subtrees","Keep edge ON DELETE rules and ent codegen in sync with migration","Retry to finish partially cascaded batches"],"tags":["go","ent","database","cascade","hard-delete","fk-constraint"],"backgroundTag":null,"analyzedSha":"20c95ad73f3a8bcb72887fea91ff31ab24fa1011","analyzedAt":"2026-08-16T01:42:55.403Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}