Marketplace Launch Errorfix
vsce package slurps your whole pnpm workspace
TLDR
If you use pnpm workspaces and run vsce package, the default .vscodeignore is not enough. vsce traverses pnpm's symlinked node_modules and pulls in every sibling package, your workspace root files, and any scripts directory. Fix: add explicit ../<sibling>/* patterns and ../../ workspace exclusions to every package's .vscodeignore.
Symptom
You run vsce package in extension/packages/core and get either:
ERROR invalid relative path: extension/../../pnpm-workspace.yaml
Or a successful package that turns out to be 55 MB because it contains:
../tafne/(the sibling extension)../pdf/(another sibling)../schema/(another)../../pnpm-workspace.yaml../../package.json../../.vscode/launch.json../../scripts/build-media.sh
Root cause
pnpm represents workspace dependencies as symlinks inside node_modules. When packages/core has node_modules/.pnpm/... with symlinks pointing at sibling packages, vsce's file traversal follows them. Most ignore patterns target single-directory exclusions (node_modules/, src/) and miss the parent-directory paths produced by symlink traversal.
The standard .vscodeignore template covers:
src/
node_modules/
tsconfig.json
.vscode/
*/.map
pnpm-lock.yaml
package-lock.json
This is fine for a standalone extension. It fails for pnpm workspaces because:
node_modules/excludes the localnode_modulesbut vsce can still resolve paths through pnpm's.pnpm/cache.- The traversal produces paths like
extension/../../pnpm-workspace.yamlwhich escape the package root. - Sibling packages appear as
../tafne/,../pdf/, etc. and need explicit patterns.
Fix
Add to every package's .vscodeignore:
# Source — only the compiled output (out/) ships
src/
tsconfig.json
Sibling workspace packages — pnpm symlinks would otherwise pull them in
../core/**
../tafne/**
../pdf/**
../schema/**
../pack/**
Workspace root files — vsce would slurp them via symlink traversal
../../*
../../.vscode/**
../../scripts/**
Dev artifacts
node_modules/
.vscode/
*/.map
*/.ts
!out/*/.d.ts
pnpm-lock.yaml
package-lock.json
.gitignore
.eslintrc*
Each sibling pattern explicitly excludes the directory by relative path. The workspace root patterns ../../ and ../../.vscode/* block traversal beyond the package's own grandparent. You list every sibling because vsce traverses symlinks individually.
After this change, vsce package core produces a 216 KB .vsix with only:
extension/
├── LICENSE.txt
├── changelog.md
├── icon.png
├── package.json
├── readme.md
├── media/vsc-bridge.js
└── out/
├── extension.js
├── auth/AuthProvider.js
├── mcp/tools.js
├── router/GinexysRouter.js
├── sync/SyncClient.js
└── webview/html-rewriter.js
Compiled output, license, readme, package manifest. Nothing else.
Guard
Always run vsce ls before vsce package. The ls subcommand prints every file the package will contain. If you see anything starting with ../, your .vscodeignore has a hole.
cd packages/core
vsce ls | head -30
If the first lines contain ../tafne/ or ../../package.json, you have not yet fixed the symlink traversal. Add more patterns. Re-run vsce ls. Iterate until the output contains only the files you intend to ship.
The other early-warning sign is package size. A standalone VS Code extension with no bundled assets should be under 1 MB. If your .vsix is 10+ MB without a clear reason (large worker scripts, embedded media), pnpm workspaces are probably leaking in.
Lesson
vsce was designed for single-package extensions with traditional node_modules. pnpm workspaces violate that assumption by representing siblings as symlinks. The ignore patterns that worked for npm and yarn projects do not transfer cleanly.
There is a --no-dependencies flag on vsce package that disables npm/yarn/pnpm dependency detection. It does not help here, because the issue is filesystem traversal of pnpm's symlink graph, not declared dependencies. The symlinks exist as physical paths, and vsce treats them as files.
The fix is purely declarative: tell vsce which paths to never look at, using the package's own relative position as the anchor. Make those exclusions exhaustive (every sibling, every workspace root file). Then verify with vsce ls before you publish.
You will run this once per extension. After that, the .vscodeignore keeps working. The fix is the cost of using a modern package manager with a tool that has not caught up.