dgraph-io/dgraph · warning

Rename failed to remove temporary file

Error message

Rename failed to remove temporary file

What it means

After a successful S3 copy, s3Handler.Rename deletes the source object; if RemoveObject fails the error is wrapped as 'Rename failed to remove temporary file'. The copy already succeeded, so the data exists at the destination, but the source (typically a temporary object) is left behind — a cleanup failure, not data loss.

Source

Thrown at worker/backup_handler.go:420

func (h *s3Handler) Rename(srcPath, dstPath string) error {
	srcPath = h.getObjectPath(srcPath)
	dstPath = h.getObjectPath(dstPath)
	src := minio.CopySrcOptions{Bucket: h.bucketName, Object: srcPath}
	dst := minio.CopyDestOptions{Bucket: h.bucketName, Object: dstPath}
	// We try copying 100 times, if it still fails, then the user should manually rename.
	err := x.RetryUntilSuccess(100, time.Second, func() error {
		if _, err := h.mc.CopyObject(context.Background(), dst, src); err != nil {
			return errors.Wrapf(err, "While renaming object in s3, copy failed")
		}
		return nil
	})
	if err != nil {
		return err
	}

	err = h.mc.RemoveObject(context.Background(), h.bucketName, srcPath, minio.RemoveObjectOptions{})
	return errors.Wrap(err, "Rename failed to remove temporary file")
}

func (h *s3Handler) getObjectPath(path string) string {
	return filepath.Join(h.objectPrefix, cleanRelPath(path))
}

View on GitHub (pinned to 759e242be6)

Solutions

  1. Verify s3:DeleteObject permission on the bucket/prefix for the worker credentials.
  2. Check for Object Lock/retention or bucket policies blocking deletion; use governance-mode bypass if authorized.
  3. Re-attempt the rename or delete the source object manually (mc rm) — destination data is already safe.
  4. Add a retry around RemoveObject and/or run periodic garbage collection of orphaned temp objects.
  5. Check the wrapped minio error code to distinguish auth vs transient failures.

Example fix

// before
err = h.mc.RemoveObject(context.Background(), h.bucketName, srcPath, minio.RemoveObjectOptions{})
return errors.Wrap(err, "Rename failed to remove temporary file")
// after
err = x.RetryUntilSuccess(10, time.Second, func() error {
    return h.mc.RemoveObject(context.Background(), h.bucketName, srcPath, minio.RemoveObjectOptions{})
})
if err != nil {
    log.Printf("warning: rename done, stale source %s needs GC", srcPath)
}
return nil
Defensive patterns

Strategy: try-catch

Try / catch

err := handler.Rename(tmp, final)
if err != nil && strings.Contains(err.Error(), "Rename failed to remove temporary file") {
    log.Printf("WARN: destination written; stale temp object %s remains — schedule cleanup", tmp)
    return nil // data is safe at destination
}

Prevention

When it happens

Trigger: minio RemoveObject returns an error after the copy succeeded: s3:DeleteObject permission missing, object locked (Object Lock/retention), versioned bucket with deny-delete policy, or a transient endpoint error on this single (un-retried) delete call.

Common situations: IAM policy grants write but not delete; S3 Object Lock in compliance mode preventing deletion of the temp object; versioned buckets with delete protection; transient 5xx on the single RemoveObject call.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/7347dfcd68f291d3. Report an issue: GitHub.