You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
mastra dev drops workspace-package exports that only tool files import #27086
DevBundler.watch() passes analysisEntries: [entryFile, <#server stub>] to getWatcherInputOptions(), then bundles every file getAllToolPaths() finds under src/mastra/tools/**. The workspace-package bundles in node_modules/.cache/ export only the names the analysis saw. A tool file that imports a name nothing else imports fails at boot:
SyntaxError: The requested module '…/node_modules/.cache/<pkg>.mjs' does not provide an export named 'X'
Bundler._bundle() (used by mastra build) includes the resolved tool paths in analyzeBundle(), so build works and dev doesn't. --tools can't work around it, because getAllToolPaths() always adds the default glob. Present in mastra 1.31.3 through 1.34.1.
Fix: call listToolsInputOptions(toolsPaths) before getWatcherInputOptions() and add ...Object.values(toolsInputOptions) to analysisEntries.
Repro: a monorepo workspace package exporting A and B; src/mastra/index.ts imports A; a file under src/mastra/tools/ imports B and is unreachable from the entry. Run mastra dev.
bug — mastra dev analyzes only the app entry + a #server stub, so the per-workspace-package .cache module never exposes exports that only tool files import, and dev fails to boot with a missing-export SyntaxError
Route
Plan fix
Severity
🟠 high — mastra dev crashes at startup for a supported monorepo shape; a one-line import workaround exists
Confidence
high — reproduced the exact reported error on published mastra@1.34.1, located the dev/build asymmetry at line level, and verified the proposed fix resolves it
Effort
low — one localized change in DevBundler.watch() that mirrors what the build path already does, plus a regression fixture
Impact
medium — dev-only; requires a tool file that is not statically reachable from the app entry and imports a workspace-package export no entry-reachable module imports
Next step
Plan the fix in DevBundler.watch() (add tool paths to analysisEntries) with a monorepo dev regression fixture containing an unregistered tool; decide on the contributor's assignment request
Understanding
Genuine bug, confirmed by reproduction. The trigger condition is narrower than the report implies and matters for the fix and its test: the tool file must not be statically reachable from the app entry (a tool discovered only by the src/mastra/tools/** glob, e.g. not registered on any agent/MCP server). A tool that an agent imports is part of the entry graph, so its imports are analyzed and dev boots fine.
Causal chain
Dev analysis entries exclude tool files. packages/cli/src/commands/dev/DevBundler.ts:124 passes analysisEntries: [entryFile, devServerAnalysisEntry]; the stub (:111-115) imports only @mastra/core/evals/scoreTraces and #server. listToolsInputOptions(toolsPaths) is called afterwards (:127) and is used only as Rollup input and by tools-watcher.
The analyzer records only observed import bindings. packages/deployer/src/build/analyze/analyzeEntry.ts:168 iterates output.importedBindings and :187-193 stores them as exports: bindings on depsToOptimize. A name imported only by an unanalyzed file never enters that set (workspace deps never get the '*' wildcard, which is reserved for unresolved dynamic imports).
That set is the cache module's export surface. workspace-deps-watcher.ts pre-transpiles each used workspace package to <pkg>/node_modules/.cache/<dep>.mjs, and packages/deployer/src/build/analyze/bundleExternals.ts:48-103 synthesizes the virtual module (export { …observed names… } from '<dep>'). Observed in the repro: the cache file contained exactly export { alpha };.
Tool output consumes that module at runtime. Dev's single watch graph still compiles tool files (input keys tools/<key>), tools-watcher writes tools.mjs importing every one, and packages/cli/src/public/templates/dev.entry.js imports #tools → the tool chunk's import { beta } from '<cache>' fails at ESM instantiation before the server starts.
Why build is unaffected:packages/deployer/src/bundler/index.ts:638-640 calls analyzeBundle([serverFile, ...additionalEntries, ...Object.values(resolvedToolsPaths)], …), i.e. build does include tool paths as analysis entries. Dev is the only gap. The issue's proposed fix matches the build behavior.
History: introduced by #18765 (4ffd33742, 2026-07-02, "fix(deployer): bundle local workspace deps in dev"), which added dev-side analysisEntries + the #server stub with the intent that watcher analysis include extra entry points so local workspace deps are discovered; tool entry points were never added to that set. No changelog entry records it.
Verified fix: hoist listToolsInputOptions(toolsPaths) above the getWatcherInputOptions() call and pass analysisEntries: [entryFile, devServerAnalysisEntry, ...Object.values(toolsInputOptions)]. Patched into the published mastra@1.34.1 bundle and re-run: dev boots, the cache module becomes export { alpha, beta };, /api/agents returns 200. Note the build path passes entryProjectRoot to listToolsInputOptions while dev does not (defaults to cwd) — harmless for analysis entries, but worth aligning.
Workaround for users: import the symbol from an entry-reachable module (the app's src/mastra/index.ts, or the agent/MCP server that registers the tool). Verified on unpatched mastra@1.34.1: dev boots and the cache exports both names. mastra build + mastra start are unaffected.
Test coverage: none for this. e2e-tests/monorepo dev suite (monorepo.test.ts:316, sharing runApiTests at :433) passes despite the template containing the same shape (apps/custom/src/mastra/tools/calculator-tool.ts imports roundToOneNumber from the @inner/hello-world barrel, which the entry never imports) — because agents/index.ts:9-11 and mcp/index.ts import that tool, pulling it into the entry graph. A regression fixture must therefore add a tool file that nothing imports. No unit test asserts dev depsToOptimize/workspaceMap contents or cache-module export surfaces.
Risk to plan around: more analysis entries means more analyzer work per dev start; #12843 (dev hang in large monorepos via recursive analyzeBundle) came from this same function. Tool files are already in the watch graph, so the added cost should be mostly shared — worth a startup-time sanity check on a large monorepo.
Related:#27033 (build fails for versionless workspace packages), #26540 (dev fails when an apiRoute imports a raw-TS workspace package), #19380 (bundler.transpilePackages ignored), #22892 (per-workspace .cache is consumer-shaped), #26321, #20248, #12843. Re-checked 2026-10-15 after a new comment: still no PR references #27086, and origin/main (04b47753) still has analysisEntries: [entryFile, devServerAnalysisEntry] at DevBundler.ts:124, so the bug is unfixed. The new comment (@akhil9tiet asking to be assigned) adds no technical information; the verdict is unchanged.
Assumptions
Read the report literally: workspace package + tool file under src/mastra/tools/ importing a name no entry-reachable module imports.
Dev-only; mastra build and start are unaffected (build already adds tool paths as analysis entries).
Not a package-manager/resolution defect — the .cache file is generated correctly for the exports the analysis saw.
Trigger requires an unregistered/entry-unreachable tool file; a registered tool masks the bug (explains green e2e).
Severity and impact judged independently: boot crash (high) vs. narrow trigger with a one-line workaround (medium).
Domain label CLI: the change lands in packages/cli/src/commands/dev/DevBundler.ts; packages/core is untouched, so no @mastra/core.
The verified fix is the issue's proposed shape; final implementation still needs review.
The assignment request is a process matter, not new evidence; it does not change classification or route.
Open questions
Contributor @akhil9tiet asked to be assigned (2026-10-15). A maintainer must decide whether to assign them or take the fix internally.
Should the same treatment cover the other convention-discovered class dev adds via fs-routing-watcher / collectInlinedPaths (fs agents whose files nothing entry-reachable imports)? I did not investigate whether inlined fs-agent paths can hit the same missing-export gap — worth deciding scope before planning.
Reproduction
Reproduced 2026-10-15 against published packages (mastra@1.34.1, @mastra/core@1.76.0, Node 24.17.0, pnpm 12.8.1) in a scratch monorepo at /tmp/repro-27086 (throwaway, not in the repo):
apps/app/src/mastra/index.ts — import { alpha } from '@ws/lib'; export const mastra = new Mastra({});
apps/app/src/mastra/tools/uses-beta.ts — import { beta } from '@ws/lib'; export const betaValue = beta(); (nothing imports this file).
pnpm install --config.minimumReleaseAge=0 --allow-build=esbuild; run with MASTRA_PORT=4555 ./node_modules/.bin/mastra dev (invoke ./node_modules/.bin/mastra directly — pnpm exec re-verifies the lockfile and fails ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION on just-published @mastra/* packages).
Result — the reported failure verbatim:
import { beta } from '/private/tmp/repro-27086/packages/ws-lib/node_modules/.cache/@ws__lib.mjs';
^^^^
SyntaxError: The requested module '…/node_modules/.cache/@ws__lib.mjs' does not provide an export named 'beta'
Verification of the direction: with watch() locally patched to include tool paths in analysisEntries, dev boots ("mastra 1.34.1 ready in 1107 ms", API on 4112, /api/agents → 200) and the cache module becomes export { alpha, beta };. Adding import { beta } from '@ws/lib' to src/mastra/index.ts on unpatched 1.34.1 produces the same result (workaround confirmed).
Activity
dane-ai-mastra commentedon Oct 14, 2026
Thank you for opening this issue. It is waiting for maintainer triage or approval.
Please wait until maintainers remove the triage or approval label before opening a pull request.
mastra-platform commentedon Oct 15, 2026
mastra devanalyzes only the app entry + a#serverstub, so the per-workspace-package.cachemodule never exposes exports that only tool files import, and dev fails to boot with a missing-exportSyntaxErrormastra devcrashes at startup for a supported monorepo shape; a one-line import workaround existsmastra@1.34.1, located the dev/build asymmetry at line level, and verified the proposed fix resolves itDevBundler.watch()that mirrors what the build path already does, plus a regression fixtureDevBundler.watch()(add tool paths toanalysisEntries) with a monorepo dev regression fixture containing an unregistered tool; decide on the contributor's assignment requestUnderstanding
Genuine bug, confirmed by reproduction. The trigger condition is narrower than the report implies and matters for the fix and its test: the tool file must not be statically reachable from the app entry (a tool discovered only by the
src/mastra/tools/**glob, e.g. not registered on any agent/MCP server). A tool that an agent imports is part of the entry graph, so its imports are analyzed and dev boots fine.Causal chain
packages/cli/src/commands/dev/DevBundler.ts:124passesanalysisEntries: [entryFile, devServerAnalysisEntry]; the stub (:111-115) imports only@mastra/core/evals/scoreTracesand#server.listToolsInputOptions(toolsPaths)is called afterwards (:127) and is used only as Rollupinputand bytools-watcher.packages/deployer/src/build/analyze/analyzeEntry.ts:168iteratesoutput.importedBindingsand:187-193stores them asexports: bindingsondepsToOptimize. A name imported only by an unanalyzed file never enters that set (workspace deps never get the'*'wildcard, which is reserved for unresolved dynamic imports).workspace-deps-watcher.tspre-transpiles each used workspace package to<pkg>/node_modules/.cache/<dep>.mjs, andpackages/deployer/src/build/analyze/bundleExternals.ts:48-103synthesizes the virtual module (export { …observed names… } from '<dep>'). Observed in the repro: the cache file contained exactlyexport { alpha };.inputkeystools/<key>),tools-watcherwritestools.mjsimporting every one, andpackages/cli/src/public/templates/dev.entry.jsimports#tools→ the tool chunk'simport { beta } from '<cache>'fails at ESM instantiation before the server starts.Why build is unaffected:
packages/deployer/src/bundler/index.ts:638-640callsanalyzeBundle([serverFile, ...additionalEntries, ...Object.values(resolvedToolsPaths)], …), i.e. build does include tool paths as analysis entries. Dev is the only gap. The issue's proposed fix matches the build behavior.History: introduced by #18765 (
4ffd33742, 2026-07-02, "fix(deployer): bundle local workspace deps in dev"), which added dev-sideanalysisEntries+ the#serverstub with the intent that watcher analysis include extra entry points so local workspace deps are discovered; tool entry points were never added to that set. No changelog entry records it.Verified fix: hoist
listToolsInputOptions(toolsPaths)above thegetWatcherInputOptions()call and passanalysisEntries: [entryFile, devServerAnalysisEntry, ...Object.values(toolsInputOptions)]. Patched into the publishedmastra@1.34.1bundle and re-run: dev boots, the cache module becomesexport { alpha, beta };,/api/agentsreturns 200. Note the build path passesentryProjectRoottolistToolsInputOptionswhile dev does not (defaults tocwd) — harmless for analysis entries, but worth aligning.Workaround for users: import the symbol from an entry-reachable module (the app's
src/mastra/index.ts, or the agent/MCP server that registers the tool). Verified on unpatchedmastra@1.34.1: dev boots and the cache exports both names.mastra build+mastra startare unaffected.Test coverage: none for this.
e2e-tests/monorepodev suite (monorepo.test.ts:316, sharingrunApiTestsat:433) passes despite the template containing the same shape (apps/custom/src/mastra/tools/calculator-tool.tsimportsroundToOneNumberfrom the@inner/hello-worldbarrel, which the entry never imports) — becauseagents/index.ts:9-11andmcp/index.tsimport that tool, pulling it into the entry graph. A regression fixture must therefore add a tool file that nothing imports. No unit test asserts devdepsToOptimize/workspaceMapcontents or cache-module export surfaces.Risk to plan around: more analysis entries means more analyzer work per dev start; #12843 (dev hang in large monorepos via recursive
analyzeBundle) came from this same function. Tool files are already in the watch graph, so the added cost should be mostly shared — worth a startup-time sanity check on a large monorepo.Related: #27033 (build fails for versionless workspace packages), #26540 (dev fails when an apiRoute imports a raw-TS workspace package), #19380 (
bundler.transpilePackagesignored), #22892 (per-workspace.cacheis consumer-shaped), #26321, #20248, #12843. Re-checked 2026-10-15 after a new comment: still no PR references #27086, andorigin/main(04b47753) still hasanalysisEntries: [entryFile, devServerAnalysisEntry]atDevBundler.ts:124, so the bug is unfixed. The new comment (@akhil9tiet asking to be assigned) adds no technical information; the verdict is unchanged.Assumptions
src/mastra/tools/importing a name no entry-reachable module imports.mastra buildandstartare unaffected (build already adds tool paths as analysis entries)..cachefile is generated correctly for the exports the analysis saw.CLI: the change lands inpackages/cli/src/commands/dev/DevBundler.ts;packages/coreis untouched, so no@mastra/core.Open questions
fs-routing-watcher/collectInlinedPaths(fs agents whose files nothing entry-reachable imports)? I did not investigate whether inlined fs-agent paths can hit the same missing-export gap — worth deciding scope before planning.Reproduction
Reproduced 2026-10-15 against published packages (
mastra@1.34.1,@mastra/core@1.76.0, Node 24.17.0, pnpm 12.8.1) in a scratch monorepo at/tmp/repro-27086(throwaway, not in the repo):packages/*andapps/*.packages/ws-lib—@ws/lib,"type": "module",main: src/index.ts, exportingalpha()andbeta().apps/appdeps:mastra@1.34.1,@mastra/core@1.76.0,zod,@ws/lib: workspace:*.apps/app/src/mastra/index.ts—import { alpha } from '@ws/lib'; export const mastra = new Mastra({});apps/app/src/mastra/tools/uses-beta.ts—import { beta } from '@ws/lib'; export const betaValue = beta();(nothing imports this file).pnpm install --config.minimumReleaseAge=0 --allow-build=esbuild; run withMASTRA_PORT=4555 ./node_modules/.bin/mastra dev(invoke./node_modules/.bin/mastradirectly —pnpm execre-verifies the lockfile and failsERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATIONon just-published@mastra/*packages).Result — the reported failure verbatim:
packages/ws-lib/node_modules/.cache/@ws__lib.mjscontained only:Verification of the direction: with
watch()locally patched to include tool paths inanalysisEntries, dev boots ("mastra 1.34.1 ready in 1107 ms", API on 4112,/api/agents→ 200) and the cache module becomesexport { alpha, beta };. Addingimport { beta } from '@ws/lib'tosrc/mastra/index.tson unpatched1.34.1produces the same result (workaround confirmed).akhil9tiet commentedon Oct 15, 2026
I'd like to work on this — please assign it to me.