apache/cassandra · warning

Failed to delete {} on exit

Error message

Failed to delete {} on exit

What it means

PathUtils registers a JVM shutdown hook (DeleteOnExit) that deletes files queued via deleteOnExitIfPossible(). If deleting a single queued file fails, it logs this warning with the path and the underlying cause. It is a best-effort cleanup notification, not a thrown error: the shutdown hook swallows the throwable and continues with the remaining queued paths.

Source

Thrown at src/java/org/apache/cassandra/io/util/PathUtils.java:737

            {
                isRegistered = true;
            }
            logger.trace("Scheduling deferred {}deletion of file: {}", recursive ? "recursive " : "", path);
            (recursive ? deleteRecursivelyOnExit : deleteOnExit).add(path);
        }

        public void run()
        {
            for (Path path : deleteOnExit)
            {
                try
                {
                    if (exists(path))
                        delete(path);
                }
                catch (Throwable t)
                {
                    logger.warn("Failed to delete {} on exit", path, t);
                }
            }
            for (Path path : deleteRecursivelyOnExit)
            {
                try
                {
                    if (exists(path))
                        deleteRecursive(path);
                }
                catch (Throwable t)
                {
                    logger.warn("Failed to delete {} on exit", path, t);
                }
            }
        }
    }
    private static final DeleteOnExit ON_EXIT = new DeleteOnExit();

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Read the attached cause (t) to identify why delete failed (lock vs permissions vs race).
  2. Ensure resources holding the file (FileHandle, RandomAccessReader, mapped segments) are closed before shutdown.
  3. Remove the file explicitly during normal teardown instead of relying on delete-on-exit if it is recreated concurrently.
  4. On Windows, check for antivirus/backup processes locking the file.
  5. If harmless and recurring, suppress the specific path or downgrade handling since the JVM is exiting anyway.

Example fix

// before
File tmp = File.createTempFile("hints", ".tmp");
PathUtils.deleteOnExitIfPossible(tmp.toPath());
// after
File tmp = File.createTempFile("hints", ".tmp");
try (FileOutputStream out = new FileOutputStream(tmp)) { /* use */ }
PathUtils.delete(tmp.toPath()); // explicit deterministic cleanup instead of delete-on-exit
Defensive patterns

Strategy: try-catch

Validate before calling

// before shutdown
if (!java.nio.file.Files.isWritable(path.getParent()))
    logger.warn("Path {} will not be deletable on exit", path);

Type guard

static boolean deletable(java.nio.file.Path p) {
    return java.nio.file.Files.exists(p) && java.nio.file.Files.isWritable(p.getParent()) && !java.nio.file.Files.isDirectory(p);
}

Try / catch

try { java.nio.file.Files.deleteIfExists(path); }
catch (java.io.IOException e) { logger.warn("Failed to delete {} on exit", path, e); }

Prevention

When it happens

Trigger: A path was queued with PathUtils.deleteOnExitIfPossible/deleteAsync; at JVM shutdown the hook runs and exists(path) is true but delete(path) throws (file locked, open memory-mapped segment, permission change, or the file was recreated/deleted concurrently between the exists() check and delete()).

Common situations: Commit-log/memtable segment files still mapped or held open by a lingering thread at shutdown; temp files in test teardown with stale file handles; directory whose permissions changed; on Windows, files locked by another process.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/3aa1339cca36f722. Report an issue: GitHub.