Mintplex-Labs/anything-llm · error · Error
Access denied - parent directory outside allowed…
Error message
Access denied - parent directory outside allowed directories.
What it means
Thrown by validatePath when the target file does not exist yet (ENOENT from realpath) and the realpath of its parent directory resolves outside the allowed directories. This branch guards file-creation paths: before creating a new file, the library verifies the directory that will hold it is inside the sandbox after resolving symlinks. It is the parent-directory analogue of the symlink-escape check.
Solutions
- Resolve the parent chain with readlink -f <parent-dir> and confirm the physical path is under an allowed directory; remove the offending symlink in the parent chain.
- Move the real directory into the sandbox and use its physical path for writes.
- If the physical location must be used, add it to the library's allowed directories at initialization.
Example fix
# before
ln -s /mnt/hostdata /app/storage/anythingllm-fs/out
write_file({ path: "out/new.txt", content: "x" }) # throws
# after (real directory inside the sandbox)
mv /mnt/hostdata /app/storage/anythingllm-fs/out
write_file({ path: "out/new.txt", content: "x" }) # ok Defensive patterns
Strategy: try-catch
Validate before calling
const fs = require("fs").promises;
const path = require("path");
async function parentResolvesInsideSandbox(fileOps, target) {
const allowed = fileOps.getAllowedDirectories();
const parent = path.dirname(path.resolve(target));
const realParent = await fs.realpath(parent); // throws if parent missing -> error 323 instead
return allowed.some((r) => realParent === r || realParent.startsWith(r + path.sep));
} Try / catch
try {
await fileOps.writeFileContent(p, content);
} catch (e) {
if (e.message.includes("parent directory outside allowed directories")) {
// resolve and inspect path.dirname chain; fix symlinks, do not widen the sandbox automatically
throw new Error(`Write target's parent resolves outside sandbox: ${p}`);
}
throw e;
} Prevention
- For new-file writes, verify readlink -f of the containing directory stays under the sandbox root.
- Avoid Docker volume layouts where the sandbox path is a symlink to a host mount.
- Keep file-creation paths flat relative to the allowed root where possible.
When it happens
Trigger: write_file to sandbox-dir/link/new.txt where 'link' is a symlink whose realpath is outside the allowed roots; creating a file under a mount point that resolves (via symlink or bind) to a host path outside STORAGE_DIR/anythingllm-fs; Docker volume layouts where the workspace dir is itself a link to /host/mnt.
Common situations: Docker-compose mounts a host directory through a symlinked path; users 'relocate' the sandbox by symlinking storage/anythingllm-fs elsewhere; NFS/automount paths whose realpath differs from the mount point.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Access denied - symlink target outside allowed directories.
- Access denied - path outside allowed directories.
- Cannot copy symbolic link
- Parent directory does not exist
- Could not find exact match for edit:\n
AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18).
Data as JSON: /api/errors/8a10f10d430b2512.
Report an issue: GitHub.
Appendix: source
Thrown at server/utils/agents/aibitat/plugins/filesystem/lib.js:464
);
}
return realPath;
} catch (error) {
if (error.code === "ENOENT") {
const parentDir = path.dirname(absolute);
try {
const realParentPath = await fs.realpath(parentDir);
const normalizedParent = this.#normalizePath(realParentPath);
if (
!this.#isPathWithinAllowedDirectories(
normalizedParent,
this.#allowedDirectories
)
) {
console.log(
`[validatePath] Access denied - parent directory outside allowed directories: ${realParentPath} not in ${this.#allowedDirectories.join(", ")}`
);
throw new Error(
`Access denied - parent directory outside allowed directories.`
);
}
return absolute;
} catch {
throw new Error(`Parent directory does not exist: ${parentDir}`);
}
}
throw error;
}
}
/**
* Gets detailed file statistics.
* @param {string} filePath - Path to the file
* @returns {Promise<Object>} File statistics
*/
async getFileStats(filePath) {View on GitHub (pinned to 3aec848f28)