denoland/deno · error
Entry point must be a file: {}
Error message
Entry point must be a file: {} What it means
During declaration emission, each entrypoint specifier is converted to a local file path to place the rolled-up .d.ts (Url::to_file_path, cli/tools/bundle/mod.rs:490-496). The conversion fails for any non-file:// scheme, so remote (https://) or data: entrypoints cannot produce declarations.
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 89f33cbef2)
Solutions
- Download/mirror the remote module into the project and pass the local file as the entrypoint
- If the remote module is small, vendor it (deno vendor-style copy or deno add for jsr) and import locally
- Drop --declaration when the entrypoint must stay remote - declaration emission is local-files-only
Example fix
# before
deno bundle --declaration https://example.com/mod.ts --outdir dist
# after: local entry
Deno.writeTextFileSync('mod.ts', await (await fetch('https://example.com/mod.ts')).text());
deno bundle --declaration mod.ts --outdir dist Defensive patterns
Strategy: type-guard
Validate before calling
// Ensure every entrypoint is a local file before declaration bundling
function assertLocalEntries(entries: string[]) {
for (const e of entries) {
if (new URL(e, import.meta.url).protocol !== 'file:') {
throw new Error(`declaration bundling requires a local entry: ${e}`);
}
}
} Type guard
function isFileUrl(specifier: string): specifier is `file://${string}` {
try { return new URL(specifier).protocol === 'file:'; } catch { return false; }
} Prevention
- Vendor remote entry modules into the repo instead of bundling from URLs
- Treat URL entrypoints and --declaration as mutually incompatible in build scripts
When it happens
Trigger: 'deno bundle --declaration https://example.com/mod.ts ...' or any entry that resolves to a remote/data specifier; piping an entry via a URL shortener/CDN in a build script.
Common situations: Build scripts that consume modules straight from a URL (common with jsr/std links); migrating a remote-entry workflow to --declaration.
Related errors
- Type checking failed when generating declarations:\n{}
- No declaration file emitted for entry point: {}
- The bench function must have a name
- Unexpected third argument to Deno.bench()
- BenchContext::end() has already been invoked
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/bc40810bbbe1646b.
Report an issue: GitHub.