denoland/deno · error · FsError

too many temp files exist

Error message

too many temp files exist

What it means

Deno.makeTempFileSync() generates up to 10 candidate names (dir + prefix + 8-hex random + suffix) and creates each with an exclusive create; AlreadyExists means the name is taken and the loop retries. If all 10 attempts collide, it fails with io::ErrorKind::AlreadyExists 'too many temp files exist', wrapped with context 'tmpfile'.

Source

Thrown at ext/fs/ops.rs:1263

  for _ in 0..MAX_TRIES {
    let path = tmp_name(&mut rng, &dir, prefix.as_deref(), suffix.as_deref())?;
    // PERMISSIONS: this is fine because the dir was checked
    let path = CheckedPath::unsafe_new(Cow::Owned(path));
    match fs.open_sync(&path, open_opts) {
      Ok(_) => {
        // PERMISSIONS: ensure the absolute path is not leaked
        let path =
          strip_dir_prefix(&dir, dir_arg.as_deref(), path.into_owned_path())?;
        return path_into_string(path.into_os_string());
      }
      Err(FsError::Io(ref e)) if e.kind() == io::ErrorKind::AlreadyExists => {
        continue;
      }
      Err(e) => return Err(e).context("tmpfile"),
    }
  }

  Err(FsError::Io(io::Error::new(
    io::ErrorKind::AlreadyExists,
    "too many temp files exist",
  )))
  .context("tmpfile")
}

#[op2(stack_trace)]
#[string]
pub async fn op_fs_make_temp_file_async(
  state: Rc<RefCell<OpState>>,
  #[string] dir_arg: Option<String>,
  #[string] prefix: Option<String>,
  #[string] suffix: Option<String>,
) -> Result<String, FsOpsError> {
  let (dir, fs) =
    make_temp_check_async(state, dir_arg.as_deref(), "Deno.makeTempFile()")?;

  let open_opts = OpenOptions {

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Remove stale files matching the prefix/suffix pattern from the directory
  2. Choose a fresh prefix or suffix
  3. Omit dir to create in the OS temp directory
  4. Retry with a different prefix when AlreadyExists surfaces

Example fix

// before
const f = Deno.makeTempFileSync({ dir: './tmp', prefix: 'up-', suffix: '.part' });

// after
const f = Deno.makeTempFileSync({ dir: './tmp', prefix: `up-${Date.now()}-` });
Defensive patterns

Strategy: retry

Validate before calling

function makeTempFileSafe(opts: Deno.MakeTempOptions = {}): string {
  for (let i = 0; i < 3; i++) {
    try {
      return Deno.makeTempFileSync({ ...opts, prefix: `${opts.prefix ?? ''}${Date.now()}-` });
    } catch (e) {
      if (!(e instanceof Error) || !/too many temp files exist/.test(e.message)) throw e;
    }
  }
  throw new Error('temp file creation exhausted retries');
}

Try / catch

try {
  path = Deno.makeTempFileSync({ dir, prefix, suffix });
} catch (e) {
  if (e instanceof Error && /too many temp files exist/.test(e.message)) {
    path = Deno.makeTempFileSync({ dir, prefix: `${prefix}${crypto.randomUUID().slice(0, 8)}-`, suffix });
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Deno.makeTempFileSync({ dir, prefix, suffix }) where every generated name matches an existing file — a stubbed filesystem in tests that always answers AlreadyExists, or a directory pre-seeded with the exact prefix/suffix + hex pattern.

Common situations: Test doubles intercepting file creation; file-sync or antivirus agents racing creation; nearly impossible naturally because tmp_name draws from a 64-bit random space — real occurrences almost always involve mocking or name squatting.

Related errors


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