cloudreve/cloudreve · error

failed to delete direct links of files %v: %w

Error message

failed to delete direct links of files %v: %w

What it means

Wraps a failure to hard-delete direct-link rows attached to the files being removed (DirectLink.Delete().Where(directlink.FileIDIn(...)) under SkipSoftDelete). Direct links are signed URLs bypassing shares; they must be physically removed with the file.

Source

Thrown at inventory/file.go:596

	hardDeleteCtx := schema.SkipSoftDelete(ctx)
	fileGroups, chunks := f.batchInCondition(intsets.MaxInt, 10, 1,
		lo.Map(files, func(file *ent.File, index int) int {
			return file.ID
		}),
	)

	for i, group := range fileGroups {
		// 4. Delete shares/metadata/directlinks if needed;
		if _, err := f.client.Share.Delete().Where(share.HasFileWith(group)).Exec(ctx); err != nil {
			return nil, nil, fmt.Errorf("failed to delete shares of files %v: %w", group, err)
		}

		if _, err := f.client.Metadata.Delete().Where(metadata.FileIDIn(chunks[i]...)).Exec(schema.SkipSoftDelete(ctx)); err != nil {
			return nil, nil, fmt.Errorf("failed to delete metadata of files %v: %w", group, err)
		}

		if _, err := f.client.DirectLink.Delete().Where(directlink.FileIDIn(chunks[i]...)).Exec(hardDeleteCtx); err != nil {
			return nil, nil, fmt.Errorf("failed to delete direct links of files %v: %w", group, err)
		}

		// 5. Delete files.
		if _, err := f.client.File.Delete().Where(group).Exec(hardDeleteCtx); err != nil {
			return nil, nil, fmt.Errorf("failed to delete files %v: %w", group, err)
		}
	}

	return toBeRecycled, storageReduced, nil
}

func (f *fileClient) Copy(ctx context.Context, args *CopyParameter) (map[int][]*ent.File, StorageDiff, error) {
	files := args.Files
	dstMap := args.DstMap
	pageSize := capPageSize(f.maxSQlParam, intsets.MaxInt, 10)
	// 1. Copy files and metadata
	copyFileStm := lo.Map(files, func(file *ent.File, index int) *ent.FileCreate {

View on GitHub (pinned to 20c95ad73f)

Solutions

  1. Unwrap the underlying cause; retry deadlock-class failures
  2. Re-invoke the delete to finish remaining batches
  3. Review any schema-level FKs added to direct_links
  4. Tolerate 404-style outcomes in link consumers when a file is removed mid-download

Example fix

// before
inv.Delete(ctx, files, props)

// after
if err := deleteAll(files); isDeadlockOrConnReset(err) {
    // links are removed per batch; second pass completes the remainder
    err = deleteAll(files)
}
Defensive patterns

Strategy: try-catch

Try / catch

if _, _, err := inv.Delete(ctx, files, props); err != nil {
    log.WithError(err).Warn("direct-link purge failed; rerunning delete to finish")
    if _, err2 := inv.Delete(ctx, remainingFiles(ctx, files), props); err2 != nil {
        return errors.Join(err, err2)
    }
}

Prevention

When it happens

Trigger: Concurrent creation or use of a direct link on a file being deleted (lock contention); FK RESTRICT from customized schema; connection/context failure mid-cascade.

Common situations: Download via direct link racing file deletion; large-batch deletes crossing a DB restart; schema customization adding FKs to the direct_links table.

Related errors


AI-assisted analysis of cloudreve/cloudreve@20c95ad73f (2026-08-16). Data as JSON: /api/errors/3c24046380303a8e. Report an issue: GitHub.