{"record":{"id":"f23b76160a7d1218","repo":"alibaba/arthas","slug":"failed-to-prepare-mcp-upload-directory","errorCode":null,"errorMessage":"Failed to prepare MCP upload directory","messagePattern":"Failed to prepare MCP upload directory","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"core/src/main/java/com/taobao/arthas/core/mcp/tool/function/basic1000/UploadFileTool.java","lineNumber":362,"sourceCode":"\n    private static Path prepareUploadRoot(Path root) {\n        if (root == null) {\n            throw new IllegalArgumentException(\"uploadRoot must not be null\");\n        }\n        try {\n            Path normalized = root.toAbsolutePath().normalize();\n            if (Files.isSymbolicLink(normalized)) {\n                throw new IllegalArgumentException(\"uploadRoot must not be a symbolic link\");\n            }\n            Files.createDirectories(normalized);\n            if (!Files.isDirectory(normalized, LinkOption.NOFOLLOW_LINKS)) {\n                throw new IllegalArgumentException(\"uploadRoot must be a directory\");\n            }\n            Path realRoot = normalized.toRealPath();\n            setDirectoryPermissions(realRoot);\n            return realRoot;\n        } catch (IOException e) {\n            throw new IllegalStateException(\"Failed to prepare MCP upload directory\", e);\n        }\n    }\n\n    private static Path createDefaultUploadRoot() {\n        try {\n            return Files.createTempDirectory(\"arthas-mcp-uploads-\");\n        } catch (IOException e) {\n            throw new IllegalStateException(\"Failed to create MCP upload directory\", e);\n        }\n    }\n\n    private static void setDirectoryPermissions(Path directory) throws IOException {\n        try {\n            Files.setPosixFilePermissions(directory, DIRECTORY_PERMISSIONS);\n        } catch (UnsupportedOperationException ignored) {\n            // 当前文件系统不支持 POSIX 权限。\n        }\n    }","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/alibaba/arthas/blob/21cf2e9ba52b305290be7223b980ff504bb9cb5b/core/src/main/java/com/taobao/arthas/core/mcp/tool/function/basic1000/UploadFileTool.java#L344-L380","documentation":"prepareUploadRoot wraps any IOException during upload directory setup (createDirectories, toRealPath, setDirectoryPermissions) into an IllegalStateException. This occurs during UploadFileTool construction (constructor line 67), not during individual file uploads. The constructor rejects symlinks, non-directory paths, and permission failures.","triggerScenarios":"Constructing UploadFileTool with a custom uploadRoot path where Files.createDirectories fails, toRealPath fails, or the normalized path is a symlink or not a directory. Also triggered if setDirectoryPermissions hits an IOException (not just UnsupportedOperationException).","commonSituations":"Configured upload path is on a read-only filesystem; a parent path component is a regular file not a directory; insufficient OS permissions; disk full; the path is a symlink (rejected at line 351-353).","solutions":["Ensure the upload root path is creatable and writable by the JVM process.","Check that no regular file occupies the path or any required parent.","Verify the path is not a symlink (symlinks are explicitly rejected).","Remove the custom uploadRoot and let the tool use the default temp directory.","Fix filesystem permissions or mount the target volume read-write."],"exampleFix":"// before: custom root on a read-only mount or occupied by a file\nnew UploadFileTool(Paths.get(\"/readonly/uploads\"), ...)\n// after: use a writable path or the default constructor\nnew UploadFileTool()  // uses Files.createTempDirectory automatically","handlingStrategy":"try-catch","validationCode":"// Before constructing UploadFileTool with a custom root, verify the path\nPath root = customUploadRoot.toAbsolutePath().normalize();\nif (Files.isSymbolicLink(root)) {\n    throw new IllegalArgumentException(\"uploadRoot must not be a symbolic link\");\n}\nFiles.createDirectories(root);\nif (!Files.isDirectory(root, LinkOption.NOFOLLOW_LINKS)) {\n    throw new IllegalArgumentException(\"uploadRoot must be a directory\");\n}\nif (!Files.isWritable(root)) {\n    throw new IllegalArgumentException(\"uploadRoot is not writable: \" + root);\n}","typeGuard":null,"tryCatchPattern":"try {\n    UploadFileTool tool = new UploadFileTool(uploadRoot, maxFileBytes, maxTotalBytes);\n} catch (IllegalStateException e) {\n    if (e.getMessage().equals(\"Failed to prepare MCP upload directory\")) {\n        // IO failure during upload directory setup — check permissions, disk, symlinks\n        logger.error(\"Upload root setup failed\", e.getCause());\n    }\n}","preventionTips":["Verify the upload root path is writable and not a symlink before constructing UploadFileTool.","Ensure no regular file occupies the target path or any parent.","Prefer the default constructor (temp directory) if no specific upload root is required.","Run a write-test on the directory before application startup."],"tags":["upload","filesystem","initialization","io","arthas-mcp"],"backgroundTag":null,"analyzedSha":"21cf2e9ba52b305290be7223b980ff504bb9cb5b","analyzedAt":"2026-08-14T00:57:07.243Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}