denoland/deno · error
workspace root is not a local directory
Error message
workspace root is not a local directory
What it means
`deno check` (native type-checker path) converts the workspace root URL to a local directory path because the whole native pipeline (generated tsconfig, incremental cache keyed by paths) assumes a real filesystem root. If the workspace root is not a `file://` URL, the conversion fails and checking aborts.
Solutions
- Run `deno check` from a real local directory that contains (or is covered by) a local deno.json/deno.jsonc
- Verify the project root is an actual on-disk directory and not a virtual/remote mount
- If the setup looks valid and it still fails, attach `deno info` output and report an issue
Defensive patterns
Strategy: validation
Validate before calling
// Preflight for scripts that drive deno check
const cwd = Deno.cwd();
const info = Deno.statSync(cwd);
if (!info.isDirectory) {
throw new Error("deno check requires a local directory workspace root");
} Prevention
- Run deno check from a real project directory with a local deno.json
- Avoid virtual/remote mounts as the workspace root
- Report valid setups that still trigger it, with `deno info` output
When it happens
Trigger: A workspace whose root resolves to a non-file URL — configuration discovered from a remote/virtual context, or embedded/sandboxed hosts where the project root is not a local directory on disk.
Common situations: Rare: running deno check inside unusual sandboxes, containers with virtual mounts, or environments where cwd/config resolution yields a non-file root. Everyday local projects never hit it.
Related errors
- A deno.json file could not be found or created
- Bench attempted to exit with exit code
- Invalid YAML
- BenchContext::end() has already been invoked
- Both 'cert' and 'key' must be provided to enable HTTPS
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/753b5fba7be78eb0.
Report an issue: GitHub.
Appendix: source
Thrown at cli/tools/check.rs:73
check_flags: CheckFlags,
) -> Result<(), AnyError> {
if check_flags.doc || check_flags.doc_only {
// Doc snippet extraction was handled by Deno 2.x's forked tsc; the native
// compiler does not type-check markdown/JSDoc snippets yet.
log::warn!(
"{} --doc/--doc-only is not yet supported by the native type checker and will be ignored",
colors::yellow("Warning")
);
}
let factory = CliFactory::from_flags(flags.clone());
let cli_options = factory.cli_options()?;
let project_root = cli_options
.workspace()
.root_dir_url()
.to_file_path()
.map_err(|_| {
deno_core::anyhow::anyhow!("workspace root is not a local directory")
})?;
// Build the module graph over the requested roots (or the whole project).
// Deno owns resolution: this drives deno's own graph diagnostics (missing
// modules + hints) and the incremental type-check cache, so we can skip the
// external compiler entirely when nothing it sees has changed.
// Resolve the requested roots the same way `deno check` always has:
// globs are expanded, workspace `exclude` is applied, and
// `include_ignored_specified: false` means an explicitly-passed excluded file
// is skipped rather than force-checked. An empty result is not an error - it
// just means there's nothing to check (e.g. every match was excluded), which
// deno reports as a warning and a clean exit.
let graph_container = factory.main_module_graph_container().await?;
let mut roots = graph_container.collect_specifiers(
&check_flags.files,
crate::graph_container::CollectSpecifiersOptions {
include_ignored_specified: false,
},View on GitHub (pinned to 9ad36f7a2c)