diff --git a/modules/git/repo_index.go b/modules/git/repo_index.go
index 83905700987..f45b6e61919 100644
--- a/modules/git/repo_index.go
+++ b/modules/git/repo_index.go
@@ -50,25 +50,35 @@ func (repo *Repository) readTreeToIndex(id ObjectID, indexFilename ...string) er
 }
 
 // ReadTreeToTemporaryIndex reads a treeish to a temporary index file
-func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (filename, tmpDir string, cancel context.CancelFunc, err error) {
-	tmpDir, err = os.MkdirTemp("", "index")
-	if err != nil {
-		return filename, tmpDir, cancel, err
-	}
+func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (tmpIndexFilename, tmpDir string, cancel context.CancelFunc, err error) {
+	defer func() {
+		// if error happens and there is a cancel function, do clean up
+		if err != nil && cancel != nil {
+			cancel()
+			cancel = nil
+		}
+	}()
 
-	filename = filepath.Join(tmpDir, ".tmp-index")
-	cancel = func() {
-		err := util.RemoveAll(tmpDir)
-		if err != nil {
-			log.Error("failed to remove tmp index file: %v", err)
+	removeDirFn := func(dir string) func() { // it can't use the return value "tmpDir" directly because it is empty when error occurs
+		return func() {
+			if err := util.RemoveAll(dir); err != nil {
+				log.Error("failed to remove tmp index dir: %v", err)
+			}
 		}
 	}
-	err = repo.ReadTreeToIndex(treeish, filename)
+
+	tmpDir, err = os.MkdirTemp("", "index")
 	if err != nil {
-		defer cancel()
-		return "", "", func() {}, err
+		return "", "", nil, err
 	}
-	return filename, tmpDir, cancel, err
+
+	tmpIndexFilename = filepath.Join(tmpDir, ".tmp-index")
+	cancel = removeDirFn(tmpDir)
+	err = repo.ReadTreeToIndex(treeish, tmpIndexFilename)
+	if err != nil {
+		return "", "", cancel, err
+	}
+	return tmpIndexFilename, tmpDir, cancel, err
 }
 
 // EmptyIndex empties the index