databendlabs/databend · error · PermissionError
Access denied: is outside allowed directories
Error message
Access denied: {target} is outside allowed directories What it means
Raised by the script-UDF Python sandbox's _ensure_allowed guard when a file open targets a path that is not relative to any directory in ALLOWED_BASES (registered allowed roots plus interpreter prefix directories). It is a deliberate sentinel security check that blocks UDF scripts from reading or writing files outside the whitelisted directories; the offending path is reported in {target}.
Solutions
- Check the failing key text in the wrapped inner error and confirm the first segment is a plain decimal u64.
- Fix the code path that generates the seq prefix; it must write the u64 seq as the first segment.
- Migrate keys written by incompatible versions.
Example fix
// before
assert!("abc/queue/x".parse_key_ok());
// after
let seq: u64 = key.split('/').next().unwrap().parse().map_err(|_| skip_key())?; Defensive patterns
Strategy: validation
Validate before calling
let seq_ok = key.split('/').next().map(|s| s.parse::<u64>().is_ok()).unwrap_or(false);
if !seq_ok { return skip(); } Type guard
fn seq_of(key: &str) -> Option<u64> { key.split('/').next()?.parse().ok() } Try / catch
match PermitKey::parse_key(key) { Err(e) if e.to_string().starts_with("failed to parse seq") => { log_corrupt(key); continue; }, other => other? } Prevention
- Write seq numbers with a single canonical u64 Display path
- Validate keys after deserializing from the meta store
- Add a migration test when changing key formats
When it happens
Trigger: A key like 'notanumber/queue/x' or a seq overflowing u64 is passed to PermitKey::parse_key.
Common situations: Manually crafted keys; corrupted/truncated first segment; an older writer format that did not prefix with a numeric seq.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Unsupported format for
- Unsupported source type. Expected path, pandas.DataFrame…
- rename_database: src (db) should exist
- internal error: expect TxnGetResponseGet of get database…
- internal error: expect some TxnGetResponseGet, but got
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/e9b96f1b942c5546.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/script_udf_support/src/transform_udf_script.rs:586
if path:
ALLOWED_BASES.add(Path(path))
for prefix in (sys.prefix, sys.exec_prefix, sys.base_prefix, sys.base_exec_prefix):
if prefix:
base_path = Path(prefix)
ALLOWED_BASES.add(base_path)
ALLOWED_BASES.add(base_path / f"lib/python{sys.version_info.major}.{sys.version_info.minor}")
_original_open = open
_original_os_open = os.open if hasattr(os, 'open') else None
def _ensure_allowed(file_path: Path, target: str):
for base in ALLOWED_BASES:
try:
file_path.relative_to(base)
return
except ValueError:
continue
raise PermissionError(f"Access denied: {target} is outside allowed directories")
def safe_open(file, mode='r', **kwargs):
file_path = Path(file).resolve()
_ensure_allowed(file_path, file)
return _original_open(file, mode, **kwargs)
def safe_os_open(path, flags, mode=0o777):
file_path = Path(path).resolve()
_ensure_allowed(file_path, path)
return _original_os_open(path, flags, mode)
builtins.open = safe_open
if _original_os_open:
os.open = safe_os_open
dangerous_modules = ['subprocess', 'os.system', 'eval', 'exec', 'compile']
for module in dangerous_modules:
if module in sys.modules:View on GitHub (pinned to 288d84d76e)