denoland/deno · error · anyhow::Error

Invalid declaration file path

Error message

Invalid declaration file path

What it means

When placing a declaration next to a `--output` file, the code needs the declaration path's final component via `path.file_name()`; for degenerate paths (a filesystem root, or a path ending in `..`) it returns None and this guard fires. It is a defensive check against malformed tsc-reported output paths.

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 89f33cbef2)

Solutions

  1. Re-run without -o (default placement next to sources) to see whether the malformed path reproduces
  2. If it reproduces, capture the command, inputs, and printed path and report an issue to the deno repository
Defensive patterns

Strategy: fallback

Try / catch

# shell: retry without -o placement if the defensive guard trips
if ! deno transpile mod.ts --declaration -o out/mod.js 2>err.log; then
  grep -q "Invalid declaration file path" err.log && deno transpile mod.ts --declaration  # default placement next to source
fi

Prevention

When it happens

Trigger: A declaration file name reported by the native compiler that has no final component while using -o. Practically unreachable through normal CLI use.

Common situations: Not user-triggered in practice; would indicate corrupt/abnormal tsc output or a path-manipulation bug in deno itself.

Related errors


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