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

  1. Move/copy the file under conductor.file-storage.parentDir (or an allowed-directories entry).
  2. Add the directory to conductor.document-access-policy.allowed-directories (supports ~ expansion), e.g. /data/imports/.
  3. 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

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

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/7a5d0668103dcc43. Report an issue: GitHub.