denoland/deno · error

On Windows an `options` argument is required if the target d

Error message

On Windows an `options` argument is required if the target does not exist

What it means

On Windows, when Deno.symlink()/symlinkSync() is called without options, Deno stats oldpath to infer the link type; if fs::metadata returns NotFound (the target does not exist), inference is impossible and the call fails with io::ErrorKind::InvalidInput 'On Windows an `options` argument is required if the target does not exist' (ext/fs/std_fs.rs:1240). Unix allows dangling symlinks, so this is Windows-specific.

Source

Thrown at ext/fs/std_fs.rs:1240

  let file_type = match file_type {
    Some(file_type) => file_type,
    None => {
      let old_meta = fs::metadata(oldpath);
      match old_meta {
        Ok(metadata) => {
          if metadata.is_file() {
            FsFileType::File
          } else if metadata.is_dir() {
            FsFileType::Directory
          } else {
            return Err(FsError::Io(io::Error::new(
              io::ErrorKind::InvalidInput,
              "On Windows the target must be a file or directory",
            )));
          }
        }
        Err(err) if err.kind() == io::ErrorKind::NotFound => {
          return Err(FsError::Io(io::Error::new(
            io::ErrorKind::InvalidInput,
            "On Windows an `options` argument is required if the target does not exist",
          )));
        }
        Err(err) => return Err(err.into()),
      }
    }
  };

  match file_type {
    FsFileType::File => {
      std::os::windows::fs::symlink_file(oldpath, newpath)?;
    }
    FsFileType::Directory => {
      std::os::windows::fs::symlink_dir(oldpath, newpath)?;
    }
    FsFileType::Junction => {
      junction::create(oldpath, newpath)?;

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Create the target first, then the symlink
  2. Always pass { type: 'file' } or { type: 'dir' } on Windows when the target may be absent
  3. Gate dangling-link behavior on Deno.build.os !== 'windows'

Example fix

// before
Deno.symlinkSync('./config.toml', 'link.toml'); // config.toml missing, Windows

// after
Deno.symlinkSync('./config.toml', 'link.toml', { type: 'file' });
Defensive patterns

Strategy: validation

Validate before calling

function ensureSymlinkable(target: string, link: string): void {
  const onWindows = Deno.build.os === 'windows';
  let type: 'file' | 'dir' | undefined;
  if (onWindows) {
    try {
      type = Deno.statSync(target).isDirectory ? 'dir' : 'file';
    } catch {
      type = undefined; // target missing: caller must decide the link type
    }
  }
  if (onWindows && !type) {
    throw new Error(
      `Windows cannot infer link type; pass { type } or create the target first: ${target}`,
    );
  }
  Deno.symlinkSync(target, link, type ? { type } : undefined);
}

Type guard

async function targetExists(target: string): Promise<boolean> {
  try {
    await Deno.stat(target);
    return true;
  } catch {
    return false;
  }
}

Prevention

When it happens

Trigger: Deno.symlinkSync('./config.toml', 'link.toml') before ./config.toml exists; installers pre-creating links to paths a later setup step will materialize; any code relying on dangling symlinks on Windows.

Common situations: Cross-platform scripts developed on macOS/Linux (dangling links fine) breaking on Windows; dotfile managers creating links before stowing files.

Related errors


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