paperclipai/paperclip · error · PluginSandboxError

Failed to read sandbox module

Error message

Failed to read sandbox module '${modulePath}': ${error instanceof Error ? error.message : String(error)}

What it means

I/O guard in readModuleSourceSync: reading the resolved module file threw (permissions, vanished file, encoding issue); the raw error is wrapped with the module path. The unreadable module file is at fault.

Solutions

  1. Fix the file read failure for the sandbox module (permissions, missing file, or I/O error) per the wrapped message.
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at server/src/services/plugin-runtime-sandbox.ts:202 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18). Data as JSON: /api/errors/207e2c3e08dccef6. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/plugin-runtime-sandbox.ts:202

  }

  throw new PluginSandboxError(`Unable to resolve module import at path '${candidatePath}'`);
}

/**
 * True when `targetPath` is inside `rootPath` (or equals rootPath), false otherwise.
 * Uses `path.relative` so sibling-prefix paths (e.g. `/root-a` vs `/root`) cannot bypass checks.
 */
function isWithinRoot(targetPath: string, rootPath: string): boolean {
  const relative = path.relative(rootPath, targetPath);
  return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
}

function readModuleSourceSync(modulePath: string): string {
  try {
    return readFileSync(modulePath, "utf8");
  } catch (error) {
    throw new PluginSandboxError(
      `Failed to read sandbox module '${modulePath}': ${error instanceof Error ? error.message : String(error)}`,
    );
  }
}

function normalizeModuleExports(exportsValue: unknown): Record<string, unknown> {
  if (typeof exportsValue === "object" && exportsValue !== null) {
    return exportsValue as Record<string, unknown>;
  }

  return { default: exportsValue };
}

/**
 * Lightweight guard to reject ESM syntax in the VM CommonJS loader.
 */
function looksLikeEsm(code: string): boolean {
  return /(^|\n)\s*import\s+/m.test(code) || /(^|\n)\s*export\s+/m.test(code);

View on GitHub (pinned to 120ae5428f)