{"record":{"id":"5a053aebeeba7d99","repo":"alibaba/spring-ai-alibaba","slug":"failed-to-delete-temporary-directory","errorCode":null,"errorMessage":"Failed to delete temporary directory: {}","messagePattern":"Failed to delete temporary directory: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/ShellSessionManager.java","lineNumber":203,"sourceCode":"\t\t\t\tsession = registryEntry.session();\n\t\t\t\ttempDir = registryEntry.workspacePath();\n\t\t\t\tlog.debug(\"Removed shell session from global registry for threadId: {}\", config.threadId().get());\n\t\t\t}\n\t\t} else if (session != null && config.threadId().isPresent()) {\n\t\t\t// Also remove from registry if we found it in context\n\t\t\tSESSION_REGISTRY.remove(config.threadId().get());\n\t\t}\n\n\t\tif (session != null) {\n\t\t\tsession.stop(terminationTimeout);\n\t\t\tconfig.context().remove(SESSION_INSTANCE_CONTEXT_KEY);\n\t\t}\n\n\t\tif (tempDir != null && useTemporaryWorkspace) {\n\t\t\ttry {\n\t\t\t\tdeleteDirectory(tempDir);\n\t\t\t} catch (IOException e) {\n\t\t\t\tlog.warn(\"Failed to delete temporary directory: {}\", tempDir, e);\n\t\t\t}\n\t\t\tconfig.context().remove(SESSION_PATH_CONTEXT_KEY);\n\t\t}\n\t}\n\n\t/**\n\t * Attempt to recover a shell session from the global registry.\n\t * This is used during HITL resume when the original context is lost.\n\t *\n\t * @param config the runnable config containing threadId\n\t * @return the recovered session, or null if not found\n\t */\n\tprivate ShellSession recoverSessionFromRegistry(RunnableConfig config) {\n\t\treturn config.threadId().map(threadId -> {\n\t\t\tSessionEntry entry = SESSION_REGISTRY.get(threadId);\n\t\t\tif (entry != null) {\n\t\t\t\tlog.info(\"Recovered shell session from global registry for threadId: {}. \" +\n\t\t\t\t\t\t\"Shell state (working directory, environment) is preserved.\", threadId);","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/ShellSessionManager.java#L185-L221","documentation":"ShellSessionManager.doCleanup deletes the session's temporary workspace directory when the session was created with a temporary workspace (useTemporaryWorkspace). If deleteDirectory throws IOException, this warning is logged with the directory path and the cleanup continues by removing SESSION_PATH_CONTEXT_KEY from the context. The temp dir may then be left on disk as an orphan.","triggerScenarios":"doCleanup (called from cleanup) attempts Files-style recursive deletion of tempDir and an IOException occurs — files locked or still being written by a lingering child process, permission problems, or a directory removed externally mid-deletion.","commonSituations":"1) A spawned background process from the shell session still holding files open in the temp workspace. 2) Running agents as different users (e.g. containerized) without delete permission on the created dir. 3 Read-only filesystems or disk-full edge cases. 4 Temp dirs accumulating because this warning repeats and nobody notices.","solutions":["Ensure all child processes of the shell session are terminated before cleanup so file handles are released.","Check filesystem permissions/ownership of the temp directory (java.io.tmpdir) for the user running the agent.","Monitor for the warning and add an external reaper (cron/task) to sweep orphaned temp dirs as a safety net.","Set a custom, writable workspace path instead of the default temporary workspace if the platform's tmpdir is restricted."],"exampleFix":"// before\n// processes still alive when doCleanup runs\nsession.close();\n// after\nsession.close();\nprocess.children().forEach(ProcessHandle::destroyForcibly); // release file locks\n// then doCleanup deletes tempDir successfully","handlingStrategy":"validation","validationCode":"static void verifyDeletable(Path dir) throws IOException {\n    if (dir == null || !Files.exists(dir)) return;\n    if (!Files.isWritable(dir)) throw new IOException(\"No write permission on temp dir: \" + dir);\n}","typeGuard":null,"tryCatchPattern":"try {\n    deleteDirectory(tempDir);\n} catch (IOException e) {\n    log.warn(\"Failed to delete temporary directory: {}\", tempDir, e);\n    // schedule for later cleanup or reaper\n}","preventionTips":["Kill all session child processes before deleting the workspace","Use a writable java.io.tmpdir or explicit workspace path","Run a periodic reaper to sweep orphaned temp directories","Verify filesystem permissions for the user running the agent process"],"tags":["filesystem","temp-directory","cleanup","io"],"backgroundTag":"file-write-failed","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}