denoland/deno · error · AnyError

temporary directory ancestor '{}' is owned by uid {}, not cu

Error message

temporary directory ancestor '{}' is owned by uid {}, not current uid {} or root

What it means

Before creating its temp node_modules root (`<tmp>/deno_nm`), Deno canonicalizes the temp dir and walks every ancestor, opening each with O_NOFOLLOW|O_DIRECTORY (`ensure_secure_temp_parent`, cli/util/temp.rs). If any ancestor's owner uid is neither the current effective uid nor root (0), Deno refuses to proceed — a directory another user controls could be swapped or manipulated underneath Deno's temp files.

Source

Thrown at cli/util/temp.rs:131

  }
  ensure_secure_temp_dir(path)
}

#[cfg(unix)]
fn ensure_secure_temp_parent(path: &Path) -> Result<(), AnyError> {
  use std::os::unix::fs::MetadataExt;
  use std::os::unix::fs::OpenOptionsExt;

  // SAFETY: geteuid has no preconditions.
  let current_uid = unsafe { libc::geteuid() };
  for ancestor in path.ancestors() {
    let dir = std::fs::OpenOptions::new()
      .read(true)
      .custom_flags(libc::O_NOFOLLOW | libc::O_DIRECTORY)
      .open(ancestor)?;
    let metadata = dir.metadata()?;
    if metadata.uid() != current_uid && metadata.uid() != 0 {
      bail!(
        "temporary directory ancestor '{}' is owned by uid {}, not current uid {} or root",
        ancestor.display(),
        metadata.uid(),
        current_uid
      );
    }
    let mode = metadata.mode();
    if mode & 0o022 != 0 && mode & 0o1000 == 0 {
      bail!(
        "temporary directory ancestor '{}' is writable by other users without the sticky bit",
        ancestor.display()
      );
    }
  }
  Ok(())
}

#[cfg(not(unix))]

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Point TMPDIR at a directory you own: `mkdir -p ~/tmp && export TMPDIR=~/tmp`.
  2. Or unset TMPDIR and use the system /tmp, which is root-owned with the sticky bit and passes the walk.
  3. If sharing is intended, have the admin `chown` the ancestor to your user (or a common uid).
  4. Avoid TMPDIRs under other users' home directories or foreign-uid volumes.

Example fix

# before
export TMPDIR=/srv/shared/tmp   # owned by uid 1000, you are uid 1001
deno install
# error: temporary directory ancestor '/srv/shared/tmp' is owned by uid 1000, not current uid 1001

# after
mkdir -p "$HOME/tmp" && export TMPDIR="$HOME/tmp"
deno install
Defensive patterns

Strategy: validation

Validate before calling

# pre-check every TMPDIR ancestor for foreign non-root ownership
d="$(cd "${TMPDIR:-/tmp}" && pwd -P)"; uid="$(id -u)"
while [ "$d" != "/" ]; do
  o="$(stat -c %u "$d" 2>/dev/null || echo 0)"
  if [ "$o" != "$uid" ] && [ "$o" != "0" ]; then
    echo "insecure temp ancestor: $d (uid $o)"
  fi
  d="$(dirname "$d")"
done

Prevention

When it happens

Trigger: TMPDIR/TMP pointing under a directory owned by a different non-root user: `TMPDIR=/home/otheruser/tmp` while running as your uid, a shared volume like /mnt/data/tmp chowned to a service account, or NFS mounts with uid mapping showing foreign ownership. Hit on the first `deno install`/run that needs the temp node_modules dir.

Common situations: Containers with TMPDIR set to an app-owned path; NFS/network mounts with idmapping; multi-user servers sharing scratch directories; sudo/user transition flows where the effective uid differs from the directory owner.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/747af3220782dd3b. Report an issue: GitHub.