denoland/deno · error · anyhow::Error

Invalid declaration file path

Error message

Invalid declaration file path

What it means

In `-o` (single output) mode the emitted declaration is written as base_dir + file_name (cli/tools/transpile.rs:369-374). Path::file_name() returns None only for degenerate paths that terminate in `..` or name the filesystem root, so this guard is practically unreachable through normal `deno transpile` usage — it exists to keep a malformed tsc-reported name from producing a bogus output path.

Solutions

  1. Re-run with explicit, concrete input file paths (no trailing .. segments or generated virtual paths).
  2. If it reproduces, record the exact deno transpile invocation and the tsconfig/deno.json in effect and report it upstream.
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: A tsc-reported declaration specifier whose path normalizes to something ending in `..` (pathological tsconfig references or generated virtual file names).

Common situations: Not seen in normal use; would indicate a highly unusual compiler/emit configuration.

Related errors


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

Appendix: source

Thrown at cli/tools/transpile.rs:373

  } 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
/// comment's closing `*/`, regardless of whether the original source had a
/// newline. For multi-line block comments (typically JSDoc) this collapses
/// the comment onto the same line as the following statement. This function
/// walks the emitted source and replaces that single space with a newline
/// (plus the comment's own leading indentation) when the preceding block
/// comment spans multiple lines.
fn restore_block_comment_newlines(input: &str) -> String {
  let bytes = input.as_bytes();
  let n = bytes.len();
  let mut out: Vec<u8> = Vec::with_capacity(n);

View on GitHub (pinned to 9ad36f7a2c)