alibaba/spring-ai-alibaba · warning · IllegalArgumentException

Path: outside root directory:

Error message

Path: outside root directory: 

What it means

In virtualMode, after resolving and normalizing the requested key against the backend's cwd, resolvePath() verifies the result still starts with cwd; if normalization (e.g. via symlinks-in-path or .. already caught, but also absolute segments) escapes the root it throws IllegalArgumentException("Path:<full> outside root directory: <cwd>"). This is the second layer of the virtual-root sandbox.

Source

Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/extension/file/LocalFilesystemBackend.java:109

	}

	/**
	 * Resolve a file path with security checks.
	 *
	 * When virtualMode=True, treat incoming paths as virtual absolute paths under
	 * cwd, disallow traversal (.., ~) and ensure resolved path stays within root.
	 * When virtualMode=False, preserve legacy behavior: absolute paths are allowed
	 * as-is; relative paths resolve under cwd.
	 */
	private Path resolvePath(String key) throws IllegalArgumentException {
		if (virtualMode) {
			String vpath = key.startsWith("/") ? key : "/" + key;
			if (vpath.contains("..") || vpath.startsWith("~")) {
				throw new IllegalArgumentException("Path traversal not allowed");
			}
			Path full = cwd.resolve(vpath.substring(1)).normalize();
			if (!full.startsWith(cwd)) {
				throw new IllegalArgumentException("Path:" + full + " outside root directory: " + cwd);
			}
			return full;
		}

		Path path = Paths.get(key);
		if (path.isAbsolute()) {
			return path;
		}
		return cwd.resolve(path).normalize();
	}

	@Override
	public List<FileInfo> lsInfo(String path) {
		try {
			Path dirPath = resolvePath(path);
			if (!Files.exists(dirPath) || !Files.isDirectory(dirPath)) {
				return Collections.emptyList();
			}

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Use paths located under the configured cwd/root directory.
  2. Reconfigure the backend's cwd (virtual root) to encompass the required directory tree.
  3. Normalize and prefix external absolute paths relative to the root before passing them.
  4. Check the normalized path with full.startsWith(root) in your own code first for a clearer error message.

Example fix

// before
backend.readFile("/etc/hosts"); // outside virtual root

// after
Path root = Path.of("/srv/agent-data");
Path p = root.resolve("etc/hosts").normalize();
if (!p.startsWith(root)) throw new IllegalArgumentException("outside root");
backend.readFile(root.relativize(p).toString());
Defensive patterns

Strategy: validation

Validate before calling

Path root = backendRoot;
Path p = root.resolve(key).normalize();
if (!p.startsWith(root)) {
    throw new IllegalArgumentException("Resolved path outside root: " + p);
}

Type guard

boolean isInsideRoot(String key, Path root) {
    return root.resolve(key).normalize().startsWith(root);
}

Try / catch

try {
    backend.readFile(key);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Path:")) {
        log.error("Key escaped virtual root {}", e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: resolvePath() (via dirPath/resolvedPath/searchPath/grepRaw) with a key whose normalized absolute form falls outside the configured virtual root directory.

Common situations: Configuring a cwd narrower than the paths the application actually needs; joining user input with the root such that the combined path points elsewhere; storing absolute external paths as keys.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/e8548298abe9fdfe. Report an issue: GitHub.