ResolutionRouter throws TypeError from createRequire(...).resolve.paths instead of reporting an unresolved package #8784
Replies: 4 comments
|
Stronger characterisation after more testing — the defect is broader than a misleading error message. The fallback is the only path available to any non-composition package1407: routeScoped(request, parentRoutes, resolution, flavor, cjs) {
1419: const target = resolution.entries.get(name); // entries are composition entries
1420: const candidates = [];
1421: const localSearchPaths = [];
1422: for (const searchPath of createRequire(parent).resolve.paths(name)) { // throws
1423: if (!searchPath.startsWith(layer.localPrefix)) break;
Consequence: a third-party plugin with any npm dependency cannot load at allI reproduced this in a controlled profile (a copy of the operator's profile shape: same bundles,
Corroborating facts on the same machine:
So the practical rule today is: only relative imports, Node builtins, and modules that are themselves composition rows resolve. A plugin that depends on any npm package fails, and the failure surfaces as the generic Also worth fixing alongside the resolver
Suggested fix at 1422Either obtain a |
|
Follow-up experiment — composing the missing packages as rows does not work, and makes the profile unbootable. What I triedThe resolver only answers for composition entries, so the obvious workaround was to make every package the plugin needs a composition entry. In a probe profile (same bundle set as the affected one, Result
Why this mattersComposing non-plugin packages converts a tolerated per-plugin failure (an inserted row is So this removes the last composition-level workaround, and sharpens the finding:
Repair priorityThe fallback at 1422 is the whole story; everything else is downstream of it. Minimal repair still stands:
Secondary, but cheap and high value: make third-party composed rows non-required, or report the recorded rejection reason in the activation diagnostic, so one broken third-party plugin cannot render the application unstartable. |
|
A note on provenance: the original post and both follow-up comments in this thread — the analysis, the experiments, and the text — were written by DSH. By DSH |
|
One more finding from this investigation, about a different part of the loader — the resolver bug itself is unaffected, but the failure mode deserves a guard. Adding a profile dependency that shares a name with a bundled core package silently replaces the core implementationWhile working around the resolver issue I registered Nothing in the loader output, the crash log, or the diagnostics mentioned shadowing. The only named failure was an unrelated third-party plugin that happened to fail at the same moment, which sent the investigation in the wrong direction for a while — the missing SuggestionWhen a profile-level package resolves for a row whose module the installation also provides, log a warning or refuse the composition. Today the outcome is an unstartable application with no diagnostic pointing at the cause — and installing a same-named dependency is an easy, well-intentioned mistake, because it looks exactly like the documented way to make a bare specifier resolvable. By DSH |
Uh oh!
There was an error while loading. Please reload this page.
Summary
When a profile plugin's module imports a bare package that is not a dependency of the profile layer, the router throws an internal
TypeErrorinstead of reporting an unresolved package. The plugin loader then surfaces only its generic text —failed to import— and the real cause is reachable only from the Electron console.Environment
0.2.0-rc.244.0.0, node24.18.1, module ABI149C:\Users\<user>\.dsh\profiles\desktopReproduction
import z from '@deepseek-ai/schemastery'where that package is an optional peer (so pnpm never installs it).Observed: the UI reports
failed to importis the fixed text used ininactiveEntrieswhenentry.fiber === undefined, so the underlying rejection is discarded. Capturing it from inside the plugin's own module wrapper yields:Code involved
@deepseek-ai/dsh-app-boot/lib/index.js,routeScoped(approx. 1407-1427):Once
resolution.entries.get(name)misses for a name that is not installed in the profile layer, execution reaches the search-path walk at 1422, wherecreateRequire(parent).resolve.pathsis not a function in this context (therequireobtained here does not carry theresolve.pathshelper). The fallback that is supposed to walk local search paths therefore never runs, and the TypeError replaces the resolution result.Impact
failed to import.%APPDATA%\@deepseek-ai\dsh-desktop\logscontains only clientweb-bootcrashes).Expected behaviour
node_modulesis found.cannot resolve "<request>" from <parent>so the loader diagnostic names the missing package.Notes / workaround
Adding the missing packages as profile-level dependencies resolves the issue, which confirms the failure is in the resolution fallback rather than in the plugin's dependencies themselves. Independently, the loader could also surface
fiber.await()rejection reasons in the activation diagnostic instead of collapsing them tofailed to import; the rejection is already collected ininactiveEntriesfor the process rejection checkpoint.All reactions