Problem
The SDK lazily imports @x402/fetch for the optional payments feature, but the package is not declared anywhere in package.json:
src/wrapper/x402.ts — const { x402HTTPClient } = await import("@x402/fetch"); (plus a type import)
src/wrapper/Client.ts — const { wrapFetchWithPayment } = await import("@x402/fetch");
package.json — dependencies: { "ws": "..." } only; no peerDependencies, no optionalDependencies
That makes @x402/fetch a phantom optional dependency. It works in plain Node only if the consumer coincidentally has the package installed, and it breaks any toolchain that statically analyzes the import:
- Bundlers (rollup/rolldown/vite/esbuild) fail with unresolvable-import errors unless every consumer manually externalizes
@x402/fetch.
- File tracers / snapshot builders (
@vercel/nft, and build systems that materialize dependency closures, e.g. eve 0.24+) fail hard because a configured external must be resolvable on disk: Cannot resolve external package "@x402/fetch".
- Isolated installers (bun isolated linker, pnpm) guarantee phantom resolution never works, so the runtime fallback path can't save it either.
We hit this as a hard production build failure and now carry two workarounds in our monorepo: externalizing @x402/fetch in three bundler configs and installing it as a direct dependency of the consuming app purely so build tooling can resolve an import that never executes.
Suggested fix
Declare the dependency so tooling and consumers can see it:
{
"peerDependencies": {
"@x402/fetch": "^2"
},
"peerDependenciesMeta": {
"@x402/fetch": { "optional": true }
}
}
This keeps the feature opt-in (consumers install @x402/fetch only if they use payments), lets bundlers and tracers understand the import instead of erroring, and documents the requirement instead of leaving it to runtime discovery.
Observed on agentmail@0.5.14/0.5.15 and current main.
Problem
The SDK lazily imports
@x402/fetchfor the optional payments feature, but the package is not declared anywhere inpackage.json:src/wrapper/x402.ts—const { x402HTTPClient } = await import("@x402/fetch");(plus a type import)src/wrapper/Client.ts—const { wrapFetchWithPayment } = await import("@x402/fetch");package.json—dependencies: { "ws": "..." }only; nopeerDependencies, nooptionalDependenciesThat makes
@x402/fetcha phantom optional dependency. It works in plain Node only if the consumer coincidentally has the package installed, and it breaks any toolchain that statically analyzes the import:@x402/fetch.@vercel/nft, and build systems that materialize dependency closures, e.g. eve 0.24+) fail hard because a configured external must be resolvable on disk:Cannot resolve external package "@x402/fetch".We hit this as a hard production build failure and now carry two workarounds in our monorepo: externalizing
@x402/fetchin three bundler configs and installing it as a direct dependency of the consuming app purely so build tooling can resolve an import that never executes.Suggested fix
Declare the dependency so tooling and consumers can see it:
{ "peerDependencies": { "@x402/fetch": "^2" }, "peerDependenciesMeta": { "@x402/fetch": { "optional": true } } }This keeps the feature opt-in (consumers install
@x402/fetchonly if they use payments), lets bundlers and tracers understand the import instead of erroring, and documents the requirement instead of leaving it to runtime discovery.Observed on
agentmail@0.5.14/0.5.15and currentmain.