Skip to content

mcpb pack aborts with a raw ENOENT when the directory contains a broken symlink #300

Description

@devYRPauli

mcpb pack stops with a raw ENOENT when the directory holds a broken symlink. The message names a path that the user can see on disk, so it reads as a wrong error. Nothing says the entry is a symlink, and nothing says which entry stopped the pack.

This is next to #292 in the same walk, but it is a different case. #292 is a symlink cycle and gives ELOOP. This one is a link whose target does not exist and gives ENOENT. PR #293 fixes the cycle only, so this stays after that PR lands.

Steps to reproduce

mkdir -p demo && cd demo
cat > manifest.json <<'M'
{ "manifest_version": "0.1", "name": "demo", "version": "1.0.0",
  "description": "demo", "author": { "name": "demo" },
  "server": { "type": "node", "entry_point": "index.js",
              "mcp_config": { "command": "node", "args": ["index.js"] } } }
M
touch index.js
ln -s ./nowhere dangling
mcpb pack . ../demo.mcpb

Expected

The pack skips the broken link and writes the bundle, or it stops with a message that names the link and its missing target.

Actual

Validating manifest...
Manifest schema validation passes!
ERROR: Archive error: ENOENT: no such file or directory, stat '/.../demo/dangling'

Exit code is 1 and no .mcpb file is written.

Cause

getAllFiles calls statSync(filePath) at src/node/files.ts:97. statSync follows the link and throws when the target is gone. getAllFilesWithCount has the same call at src/node/files.ts:140. Neither call is guarded, so one broken link stops the whole pack.

lstatSync reports the link itself and does not throw here. A check on stat.isSymbolicLink() before the follow would separate the two cases.

Why this happens in real trees

A broken link is normal in a working directory. node_modules/.bin keeps links to package binaries, and a prune or a partial install leaves some of them pointing at nothing. A link to a file that a later commit deleted does the same.

Workaround

Name the link in .mcpbignore. The pack then succeeds. That needs the author to already know which link is broken.

Version information

  • mcpb --version: 2.1.2
  • Built from main at 70fe3b3
  • Node v24.18.0, macOS 26.6.2

A control in the same run packs correctly. A symlink that points at a real sibling directory gives 4 files and a valid bundle. Only the broken link fails.

I am happy to send a patch for this on top of #293, so the two changes do not conflict.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions