denoland/deno · error
Native addon cache path '{}' is not a private directory
Error message
Native addon cache path '{}' is not a private directory What it means
Deno validates the native addon cache directory (created under the system temp dir for compiled/cached node native addons) for privacy before using it: symlink_metadata must be a real directory, not a symlink. Violations return ErrorKind::PermissionDenied with this message. Deno normally falls back to a fresh private tempdir, so this error surfacing means the preferred path was invalid AND the fallback could not be validated either.
Source
Thrown at ext/rt_helper/lib.rs:244
#[allow(clippy::disallowed_methods, reason = "requires real fs")]
fn create_private_native_addon_dir(path: &Path) -> std::io::Result<()> {
match fs::create_dir(path) {
Ok(()) => Ok(()),
Err(err) if err.kind() == ErrorKind::AlreadyExists => Ok(()),
Err(err) => Err(err),
}
}
fn ensure_private_native_addon_dir(path: &Path) -> std::io::Result<()> {
create_private_native_addon_dir(path)?;
validate_private_native_addon_dir(path)
}
#[allow(clippy::disallowed_methods, reason = "requires real fs")]
fn validate_private_native_addon_dir(path: &Path) -> std::io::Result<()> {
let metadata = fs::symlink_metadata(path)?;
if metadata.file_type().is_symlink() || !metadata.is_dir() {
return Err(std::io::Error::new(
ErrorKind::PermissionDenied,
format!(
"Native addon cache path '{}' is not a private directory",
path.display()
),
));
}
// Windows temp directories are normally per-user; Unix additionally
// enforces ownership and mode here.
#[cfg(unix)]
{
use std::os::unix::fs::MetadataExt;
use std::os::unix::fs::PermissionsExt;
if metadata.uid() != current_uid() {
return Err(std::io::Error::new(
ErrorKind::PermissionDenied,View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Set TMPDIR (or TMP/TEMP) to a clean, user-owned, real directory and retry: TMPDIR=$(mktemp -d).
- Remove the offending path in the temp dir (rm the symlink/file named like the Deno native addon cache) so Deno can recreate it as a real directory.
- On read-only or locked-down filesystems, move the temp dir to a writable location (e.g. emptyDir in k8s, writable layer of the container).
- If a security tool is rewriting the path, exclude the Deno cache dir from that policy.
Example fix
# before TMPDIR=/shared/tmp deno run app.ts # cache path replaced by symlink -> PermissionDenied # after export TMPDIR=$(mktemp -d) deno run app.ts
Defensive patterns
Strategy: validation
Validate before calling
import { lstatSync, statSync } from "node:fs";
import { tmpdir } from "node:os";
const t = process.env.TMPDIR ?? tmpdir();
const l = lstatSync(t, { throwIfNoEntry: false });
if (!l) throw new Error(`TMPDIR does not exist: ${t}`);
if (l.isSymbolicLink() || !l.isDirectory()) throw new Error(`TMPDIR must be a real directory, not a symlink/file: ${t}`); Try / catch
try { await run(); } catch (e) { if (/not a private directory/.test(String(e))) throw new Error(`temp dir unusable for native addon cache — set TMPDIR=$(mktemp -d). TMPDIR=${t}`); throw e; } Prevention
- Point TMPDIR at a real, user-owned directory in containers instead of shared mounts.
- Exclude Deno's temp cache paths from tools that replace directories with symlinks.
- Health-check the temp dir (exists, real dir, writable) in container entrypoints.
When it happens
Trigger: Something replaced TMPDIR/<cache-name> with a symlink or a regular file (so the preferred path fails validation) and the fallback tempdir also fails the same check — e.g. a broken, permission-restricted, or policy-managed temp filesystem where Deno cannot obtain any private directory.
Common situations: Hardened or misconfigured TMPDIR (pointing at a path managed by another tool); security agents that replace cache dirs with symlinks; container images with unusual /tmp setups; shared writable dirs tampered with by other users.
Related errors
- temporary directory ancestor '{}' is owned by uid {}, not cu
- temporary directory ancestor '{}' is writable by other users
- '{}' is not a directory
- '{}' is writable or readable by other users
- Native addon cache directory '{}' is not owned by the curren
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/576438dbb7b7266d.
Report an issue: GitHub.