paperclipai/paperclip · warning

UI parser path escapes package directory — skipping

Error message

UI parser path escapes package directory — skipping

What it means

Security guard in the plugin-loader: the ./ui-parser export path is resolved against the adapter package directory and must stay inside it (path prefix packageDir + path.sep). Absolute paths or ../ traversal that escape the package directory are rejected with this warning and the parser is skipped — preventing a malicious or misbuilt adapter from making the server read arbitrary files.

Source

Thrown at server/src/adapters/plugin-loader.ts:121

        "Adapter declares unsupported UI parser contract version — skipping UI parser",
      );
      return undefined;
    }
  } else {
    logger.info(
      { packageName },
      "Adapter has ./ui-parser export but no paperclip.adapterUiParser version — loading anyway (future versions may require it)",
    );
  }

  const uiParserExp = pkg.exports["./ui-parser"];
  const uiParserFile = typeof uiParserExp === "string"
    ? uiParserExp
    : (uiParserExp.import ?? uiParserExp.default);
  const uiParserPath = path.resolve(packageDir, uiParserFile);

  if (!uiParserPath.startsWith(packageDir + path.sep) && uiParserPath !== packageDir) {
    logger.warn(
      { packageName, uiParserFile },
      "UI parser path escapes package directory — skipping",
    );
    return undefined;
  }

  if (!fs.existsSync(uiParserPath)) {
    return undefined;
  }

  try {
    const source = fs.readFileSync(uiParserPath, "utf-8");
    logger.info(
      { packageName, uiParserFile, size: source.length },
      `Loaded UI parser from adapter package${contractVersion ? "" : " (no version declared)"}`,
    );
    return source;
  } catch (err) {

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Fix the adapter's package.json so ./ui-parser points to a file inside the package (e.g. "./dist/ui-parser.js").
  2. Rebuild/repack the adapter so the export target ships inside the package and the file exists there.
  3. If this comes from a third-party package you do not control, treat it as suspicious and audit before use.

Example fix

// adapter package.json — before
"exports": { "./ui-parser": "../../shared/ui-parser.js" }

// after
"exports": { "./ui-parser": "./dist/ui-parser.js" }
Defensive patterns

Strategy: validation

Validate before calling

import path from 'node:path';

function isContainedExport(packageDir: string, exportPath: string): boolean {
  if (path.isAbsolute(exportPath)) return false;
  const resolved = path.resolve(packageDir, exportPath);
  return resolved.startsWith(packageDir + path.sep);
}

// audit before loading a third-party adapter:
if (!isContainedExport(adapterDir, pkg.exports['./ui-parser'])) {
  throw new Error(`Refusing adapter with escaping ui-parser export`);
}

Prevention

When it happens

Trigger: An adapter's package.json exports["./ui-parser"] resolves outside the package directory — e.g. "../../shared/ui-parser.js", an absolute path, or a bundler emitting a wrong relative path during packaging.

Common situations: Hand-authored package.json exports; monorepo packaging tools rewriting relative paths; malicious third-party adapter probing for file reads.

Related errors


AI-assisted analysis of paperclipai/paperclip@a7e689b3c3 (2026-08-18). Data as JSON: /api/errors/50feba258a81880f. Report an issue: GitHub.