denoland/deno · error

Entry point must be a file

Error message

Entry point must be a file: {}

What it means

After bundling with declaration (.d.ts) emission, Deno converts each entrypoint specifier to a local file path to locate and roll up the emitted declarations. If an entrypoint is not a `file://` URL (e.g. an `https://` remote entry), the conversion fails and declaration rollup aborts.

Solutions

  1. Vendor or download the remote module and pass a local file path as the entrypoint
  2. Keep entrypoints local — move the remote module behind a thin local wrapper module and use that as the entry

Example fix

# before
deno bundle https://example.com/app.ts

# after
# vendor first, then bundle the local entry
deno vendor https://example.com/app.ts
deno bundle ./app.ts
Defensive patterns

Strategy: type-guard

Type guard

// Guard: only local file entries may be used as bundle entrypoints
function isLocalFileEntry(specifier: string): boolean {
  try {
    return new URL(specifier).protocol === "file:";
  } catch {
    return true; // bare relative paths resolve to files
  }
}
const safe = entries.every(isLocalFileEntry);

Prevention

When it happens

Trigger: Bundling with type emission enabled where an entrypoint specifier is a remote URL (e.g. `deno bundle https://example.com/mod.ts`) or any non-file specifier; imports may stay remote, but the entry itself must be local.

Common situations: Bundling a remote module straight from a URL instead of vendoring it first; alias/redirect entries that resolve to non-file URLs.

Related errors


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

Appendix: source

Thrown at cli/tools/bundle/mod.rs:492

  // Index emitted .d.ts files by their original source specifier
  // TSC emits keys like "file:///path/to/file.d.ts" - map them back to source paths
  let mut dts_by_source: std::collections::HashMap<String, String> =
    std::collections::HashMap::new();
  for (file_name, content) in &result.emitted_files {
    // Map "file:///path/to/mod.d.ts" -> normalized source path
    if let Ok(specifier) = Url::parse(file_name)
      && let Ok(file_path) = specifier.to_file_path()
    {
      let source_path = file_path.to_string_lossy().to_string();
      dts_by_source.insert(source_path, content.clone());
    }
  }

  // For each entry point, produce a single rolled-up .d.ts
  for entry_specifier in &entrypoint_specifiers {
    let entry_path = entry_specifier.to_file_path().map_err(|_| {
      deno_core::anyhow::anyhow!(
        "Entry point must be a file: {}",
        entry_specifier
      )
    })?;

    // Find the .d.ts for this entry point
    let dts_path = to_dts_path(&entry_path);
    let entry_dts = dts_by_source
      .get(&dts_path.to_string_lossy().to_string())
      .ok_or_else(|| {
        deno_core::anyhow::anyhow!(
          "No declaration file emitted for entry point: {}",
          entry_specifier
        )
      })?;

    // Flatten: resolve all `export ... from "..."` re-exports by inlining
    // the referenced declarations from other .d.ts files.

View on GitHub (pinned to 9ad36f7a2c)