paperclipai/paperclip · error · Error

ACPX module must be a bounded regular file

Error message

ACPX module must be a bounded regular file

What it means

For every non-directory entry, copy() requires it to be a regular file no larger than 16 MiB; otherwise it throws 'ACPX module must be a bounded regular file'. This rejects special files (devices, sockets, FIFOs) and oversized modules, keeping each snapshot module bounded and safely bufferable in memory.

Solutions

  1. Remove or externalize files larger than 16 MiB from the package root (ship them via another mechanism)
  2. Delete stray FIFOs/sockets/device files from the package directory
  3. Confirm the admitted root is a source package, not a build output directory containing artifacts
  4. If a large file is legitimately required, pre-process/split it below the 16 MiB bound

Example fix

// before: 40MB model shipped inside package
packages/my-app/assets/model.bin
// after: keep it out of the snapshot root
move model.bin to external storage and reference by URL
Defensive patterns

Strategy: validation

Validate before calling

for (const f of await walk(root)) {
  const st = await fs.lstat(f);
  if (!st.isFile()) throw new Error(`special file in package: ${f}`);
  if (st.size > 16 * 1024 * 1024) throw new Error(`file >16MiB: ${f}`);
}

Try / catch

try {
  await createAcpxPrivateSnapshot({ roots: [root] });
} catch (e) {
  if (e.message.includes('bounded regular file')) {
    throw new Error(`Package ${root} contains a special or >16MiB file; clean it before snapshot`);
  }
  throw e;
}

Prevention

When it happens

Trigger: copy() walks into an entry that lstat reports as not a regular file (symlink handled earlier; so FIFOs, sockets, device nodes, or directories-as-symlink leftovers) OR a regular file whose size exceeds 16n*1024n*1024n bytes.

Common situations: A package containing large bundled assets (models, wasm blobs, media) over 16 MiB; leftover Unix sockets/FIFOs in a build directory; special files created by tests inside the package tree.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/d3571e81bb38eb9e. Report an issue: GitHub.

Appendix: source

Thrown at packages/paperclip-runner/src/drivers/acpx/private-snapshot.ts:120

      const canonical = await realpath(source);
      const mapped = mapPath(canonical);
      // Package-manager links to unqualified packages do not grant import authority.
      if (mapped) await symlink(mapped, target);
      return;
    }
    if (!within(root, await realpath(source)))
      throw new Error("ACPX snapshot escaped its package");
    if (before.isDirectory()) {
      await mkdir(target, { mode: 0o700 });
      directories.push(target);
      for (const entry of await readdir(source))
        await copy(join(source, entry), join(target, entry), root);
      if (!same(before, await lstat(source, { bigint: true })))
        throw new Error("ACPX package directory changed during snapshot");
      return;
    }
    if (!before.isFile() || before.size > 16n * 1024n * 1024n)
      throw new Error("ACPX module must be a bounded regular file");
    bytesCopied += Number(before.size);
    if (bytesCopied > MAX_PACKAGE_SNAPSHOT_BYTES)
      throw new Error("ACPX package snapshot exceeds its byte bound");
    const handle = await open(
      source,
      constants.O_RDONLY | constants.O_NOFOLLOW,
    );
    try {
      if (!same(before, await handle.stat({ bigint: true })))
        throw new Error("ACPX module changed before snapshot");
      const bytes = await readSnapshotBytes(handle, Number(before.size));
      if (
        !same(before, await handle.stat({ bigint: true })) ||
        !same(before, await lstat(source, { bigint: true }))
      ) {
        throw new Error("ACPX module changed during snapshot");
      }
      await writeFile(target, bytes, { flag: "wx", mode: 0o400 });

View on GitHub (pinned to 01ad858492)