parcel-bundler/parcel · error · napi::Error
GenericFailure
GenericFailure
Error message
resolveAsync does not support custom fs or module_dir_resolver
What it means
Thrown by resolve_async when the Resolver was constructed with a custom fs or a module_dir_resolver. The async path uses rayon::spawn and only supports the OS filesystem (supports_async is set true only when no custom fs is supplied). The check is an explicit guard before spawning, so the error fires synchronously on the call, not inside the promise.
Source
Thrown at crates/node-bindings/src/resolver.rs:283
resolve_internal(&self.resolver, self.mode, options)?;
resolve_result_to_js(env, res, invalidations, side_effects, module_type)
}
#[cfg(target_arch = "wasm32")]
#[napi]
pub fn resolve_async(&'static self) -> Result<JsObject> {
panic!("resolveAsync() is not supported in Wasm builds")
}
#[cfg(not(target_arch = "wasm32"))]
#[napi]
pub fn resolve_async(&'static self, options: ResolveOptions, env: Env) -> Result<JsObject> {
let (deferred, promise) = env.create_deferred()?;
let resolver = &self.resolver;
let mode = self.mode;
if !self.supports_async || resolver.module_dir_resolver.is_some() {
return Err(napi::Error::new(
napi::Status::GenericFailure,
"resolveAsync does not support custom fs or module_dir_resolver",
));
}
rayon::spawn(move || {
let (res, invalidations, side_effects, module_type) =
match resolve_internal(&resolver, mode, options) {
Ok(r) => r,
Err(e) => return deferred.reject(e),
};
deferred.resolve(move |env| {
resolve_result_to_js(env, res, invalidations, side_effects, module_type)
});
});
Ok(promise)View on GitHub (pinned to 59484858a1)
Solutions
- Use the synchronous resolve() method instead of resolveAsync() when a custom fs or module_dir_resolver is required.
- Drop the custom fs option (use the default OS filesystem) if you need async and can tolerate real-disk resolution.
- Drop the moduleDirResolver option and handle module directory resolution in a wrapper around sync resolve.
- If you need both custom fs and non-blocking behavior, run sync resolve() in a worker thread yourself.
Example fix
// before
const resolver = new Resolver(root, { fs: customFs, mode: 1 });
const result = await resolver.resolveAsync(opts); // throws GenericFailure
// after — use sync resolve, offload if you need non-blocking
const resolver = new Resolver(root, { fs: customFs, mode: 1 });
const result = resolver.resolve(opts); // synchronous, works with custom fs Defensive patterns
Strategy: validation
Validate before calling
// Before calling resolveAsync, confirm the Resolver was built without custom fs / module_dir_resolver
function canResolveAsync(resolverOptions) {
return resolverOptions.fs == null && resolverOptions.moduleDirResolver == null;
}
if (!canResolveAsync(originalOptions)) {
// use sync resolve instead
return resolver.resolve(opts);
}
return await resolver.resolveAsync(opts); Type guard
function resolverSupportsAsync(opts) {
return opts.fs === undefined && opts.moduleDirResolver === undefined;
} Try / catch
try {
return await resolver.resolveAsync(opts);
} catch (e) {
if (e.message.includes('does not support custom fs')) {
// fall back to synchronous resolution
return resolver.resolve(opts);
}
throw e;
} Prevention
- Remember the rule: custom fs OR moduleDirResolver disables async — no workaround inside the binding.
- If you need non-blocking resolution with a custom fs, run sync resolve() in a Node worker_thread.
- Document on your Resolver factory which mode (sync/async) each configuration supports.
- Add a unit test that asserts resolveAsync throws immediately (not in the promise) when fs is set.
When it happens
Trigger: Constructing a Resolver with options.fs (a custom JsFileSystemOptions) or options.moduleDirResolver (a function), then calling resolver.resolveAsync(opts). Either condition independently triggers the error. Using OsFileSystem (no fs option) with no module_dir_resolver allows async.
Common situations: Building a resolver over a virtual/remote filesystem and wanting non-blocking resolution; integrating a custom module directory resolver for monorepo setups and assuming it composes with async; copying a sync-configured Resolver into an async code path.
Related errors
- NotFound
- InvalidArg
- Resolvers must return an absolute path, ${resolver.name} ret
- Please provide a worker path!
- Invalid backend: ${backend}
AI-assisted analysis of parcel-bundler/parcel@59484858a1 (2026-08-13).
Data as JSON: /api/errors/a7bcdfb8c54dfabd.
Report an issue: GitHub.