conductor-oss/conductor · warning · DocumentAccessDeniedException
Access denied: path is not under any allowed directory. Allo
Error message
Access denied: path is not under any allowed directory. Allowed directories: {dirs} What it means
Thrown by DocumentAccessPolicy.checkAllowedDirectories when a local (non-http) path does not start with any effective allowed directory. The effective list is computed at startup: conductor.file-storage.parentDir (defaulting to ~/worker-payload/) plus conductor.document-access-policy.allowed-directories. Only when the list is non-empty does this allowlist enforce — meaning by default, local files must live under the file-storage tree. DocumentAccessDeniedException (SecurityException); the message lists the allowed directories.
Source
Thrown at ai/src/main/java/org/conductoross/conductor/ai/document/DocumentAccessPolicy.java:411
*/
private void checkAllowedDirectories(String originalLocation, String normalizedPath) {
List<String> dirs = effectiveAllowedDirectories;
if (dirs == null || dirs.isEmpty()) {
return;
}
// Only apply to local filesystem paths, not HTTP URLs
if (originalLocation.startsWith("http://") || originalLocation.startsWith("https://")) {
return;
}
for (String dir : dirs) {
String expandedDir = expandHome(dir.endsWith("/") ? dir : dir + "/");
if (normalizedPath.startsWith(expandedDir) || normalizedPath.equals(expandedDir)) {
return; // Path is within an allowed directory
}
}
throw new DocumentAccessDeniedException(
"Access denied: path is not under any allowed directory. "
+ "Allowed directories: "
+ dirs);
}
private String normalizeLocation(String location) {
// Strip file:// scheme
String path = location;
if (path.startsWith("file://")) {
path = path.substring(7);
}
// For HTTP URLs, extract the path component
if (path.startsWith("http://") || path.startsWith("https://")) {
try {
URI uri = URI.create(path);
return uri.getPath() != null ? uri.getPath() : "";
} catch (Exception e) {View on GitHub (pinned to cf7c3e4a8a)
Solutions
- Move/copy the file under conductor.file-storage.parentDir (or an allowed-directories entry).
- Add the directory to conductor.document-access-policy.allowed-directories (supports ~ expansion), e.g. /data/imports/.
- Confirm the path you pass is absolute and normalized so the startsWith check matches (trailing slashes matter).
Example fix
# application.yml — before (default only ~/worker-payload/)
# after — add an import location
conductor:
document-access-policy:
allowed-directories:
- /data/imports/ Defensive patterns
Strategy: validation
Validate before calling
// Confirm a local path is under an allowed dir before calling the loader
java.util.List<String> allowed = accessPolicy.getEffectiveAllowedDirectories();
String norm = java.nio.file.Path.of(path).normalize().toString();
boolean ok = allowed.stream().anyMatch(d -> {
String base = d.endsWith("/") ? d : d + "/";
return norm.startsWith(base) || norm.equals(base);
});
if (!ok) throw new IllegalArgumentException("Path not under an allowed dir: " + path); Try / catch
try {
loader.download(path);
} catch (SecurityException e) {
// add the directory to allowed-directories or move the file under parentDir
log.warn("Path outside allowed dirs {}; allowed={}", path, accessPolicy.getEffectiveAllowedDirectories());
throw e;
} Prevention
- Keep documents under conductor.file-storage.parentDir by default.
- Add extra roots to conductor.document-access-policy.allowed-directories explicitly.
- Pass absolute, normalized paths so the startsWith allowlist check matches.
When it happens
Trigger: A document loader/upload is given a local file path that lives outside ~/worker-payload/ and outside any extra allowed-directories you configured.
Common situations: A workflow reads a file from /tmp or an arbitrary absolute path that is not under the storage root; parentDir was changed and old file references now fall outside; a new import location was not added to allowed-directories.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Access denied: path matches blocked prefix '{prefix}'
- Access denied: file name '{fileName}' is blocked
- Access denied: host '{host}' is blocked
- Access denied: link-local address range is blocked (host res
- Access denied: loopback address is blocked (host resolves to
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/7a5d0668103dcc43.
Report an issue: GitHub.