denoland/deno · error · anyhow::Error

Declaration file is not under the current directory

Error message

Declaration file {} is not under the current directory

What it means

With `deno transpile --declaration --outdir <dir>`, emitted .d.ts files mirror the source tree: resolve_dts_output_path strips the current directory from each declaration path (transpile.rs:359-368). tsc reports specifiers as normalized file:// URLs, so `../` inputs collapse outside cwd and absolute inputs into other trees fail strip_prefix — Deno then cannot compute the relative layout and errors.

Solutions

  1. Run from a common ancestor (e.g. the repo root) so every input lies under the current directory.
  2. Use single-file output instead: `deno transpile --declaration --output dist/lib.js <input>` — -o places the .d.ts next to the output file without needing a relative tree.
  3. Copy or symlink the external sources under cwd for the duration of the build.

Example fix

# before — input outside cwd + --outdir
$ cd packages/app && deno transpile --declaration --outdir dist ../shared/lib.ts
error: Declaration file /repo/packages/shared/lib.d.ts is not under the current directory

# after — run from the common root, or target a single output
$ deno transpile --declaration --outdir dist packages/shared/lib.ts   # from repo root
$ deno transpile --declaration --output dist/lib.js ../shared/lib.ts   # single-file mode
Defensive patterns

Strategy: validation

Validate before calling

# Ensure all transpile inputs are under the current directory before using --outdir
for f in src/**/*.ts; do
  case "$(realpath "$f")" in
    "$(pwd)"/*) ;;
    *) echo "outside cwd: $f — use --output instead"; exit 1;;
  esac
done
deno transpile --declaration --outdir dist src/**/*.ts

Prevention

When it happens

Trigger: deno transpile --declaration --outdir dist ../shared/lib.ts from a subpackage (URL normalization resolves it outside cwd), or an absolute input like /opt/other/a.ts; also when cwd was changed with -C but inputs are given relative to another directory.

Common situations: Transpiling a sibling package's sources from an app folder; CI invoking deno from a different working directory than the sources; build scripts mixing absolute and relative inputs.

Related errors


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

Appendix: source

Thrown at cli/tools/transpile.rs:363

  tsc_file_name: &str,
  output_dir: Option<&str>,
  output_base_dir: Option<&Path>,
  cwd: &Path,
) -> Result<PathBuf, AnyError> {
  // TSC emits file names like "file:///path/to/file.d.ts"
  let path = if let Ok(specifier) = ModuleSpecifier::parse(tsc_file_name) {
    deno_path_util::url_to_file_path(&specifier).with_context(|| {
      format!("Cannot convert specifier to path: {tsc_file_name}")
    })?
  } else {
    PathBuf::from(tsc_file_name)
  };

  if let Some(outdir) = output_dir {
    // --outdir: preserve relative directory structure
    let outdir = cwd.join(outdir);
    let relative = path.strip_prefix(cwd).map_err(|_| {
      anyhow::anyhow!(
        "Declaration file {} is not under the current directory",
        path.display()
      )
    })?;
    Ok(outdir.join(relative))
  } else if let Some(base_dir) = output_base_dir {
    // -o: place .d.ts next to the output file
    let file_name = path
      .file_name()
      .ok_or_else(|| anyhow::anyhow!("Invalid declaration file path"))?;
    Ok(base_dir.join(file_name))
  } else {
    // No output specified: place next to source file
    Ok(path)
  }
}

/// SWC's code generator always writes a single space after a block

View on GitHub (pinned to 9ad36f7a2c)