paperclipai/paperclip · error

runner_provider_package_root_incompatible

runner_provider_package_root_incompatible

Error message

runner_provider_package_root_incompatible: ACPX sidecar must use the provider package dist/cli layout

What it means

acpxProviderPackageAuthority validates that the ACPX sidecar script path follows the strict provider-package layout <packageRoot>/dist/cli/acpx-runtime-sidecar.cjs. Anything else (source-tree script, renamed file, relocated install) is rejected because the code resolves the package root and dependency layout from that structure.

Source

Thrown at packages/paperclip-runner/src/live/runnerd-codex-transport.ts:2724

  throw new Error(
    `runner_local_provider_artifact_missing: ${artifact} is absent; build @paperclipai/paperclip-runner TypeScript artifacts with build:typescript before starting a local JS-backed provider`,
  );
}

function acpxProviderPackageAuthority(
  sidecarScript: string,
  ownerPackageRoot = packageRoot,
): {
  root: string;
  manifest: string;
} {
  const cliDirectory = dirname(sidecarScript);
  if (
    basename(sidecarScript) !== "acpx-runtime-sidecar.cjs" ||
    basename(cliDirectory) !== "cli" ||
    basename(dirname(cliDirectory)) !== "dist"
  ) {
    throw new Error(
      "runner_provider_package_root_incompatible: ACPX sidecar must use the provider package dist/cli layout",
    );
  }
  const sidecarPackageRoot = resolve(cliDirectory, "../..");
  // A local source build lives at <workspace>/packages/paperclip-runner and
  // resolves dependencies from <workspace>/node_modules. `pnpm deploy` makes
  // the package itself the deployment root and owns <deploy>/node_modules/.pnpm.
  // The older npm-installed portable shape nests the scoped package at
  // <deploy>/node_modules/@paperclipai/paperclip-runner. The verifier always
  // receives the directory that owns node_modules, regardless of which
  // portable shape launched the already-authenticated sidecar.
  const sourceDependencyRoot = resolve(ownerPackageRoot, "../..");
  const localDependencyRoot = existsSync(
    resolve(ownerPackageRoot, "node_modules", ".pnpm"),
  )
    ? ownerPackageRoot
    : basename(sourceDependencyRoot) === "node_modules"
      ? resolve(sourceDependencyRoot, "..")

View on GitHub (pinned to 01ad858492)

Solutions

  1. Use the sidecar script at <providerPackageRoot>/dist/cli/acpx-runtime-sidecar.cjs exactly.
  2. Rebuild/redeploy the provider package (pnpm build / pnpm deploy) so the dist/cli layout exists.
  3. Do not rename or relocate the sidecar script; if packaging differs, restore the dist/cli directory structure.
  4. If resolving from a workspace, ensure resolution goes through node_modules to the deployed package, not the raw source path.

Example fix

// before
const sidecar = 'packages/acpx/src/acpx-runtime-sidecar.cjs';
// after
const sidecar = require.resolve('acpx-provider/dist/cli/acpx-runtime-sidecar.cjs');
Defensive patterns

Strategy: validation

Validate before calling

import { basename, dirname } from 'node:path';
const ok = basename(sidecar) === 'acpx-runtime-sidecar.cjs'
  && basename(dirname(sidecar)) === 'cli'
  && basename(dirname(dirname(sidecar))) === 'dist';
if (!ok) throw new Error('sidecar must live at <pkgRoot>/dist/cli/acpx-runtime-sidecar.cjs');

Type guard

const isDistCliSidecar = (p: string): boolean =>
  basename(p) === 'acpx-runtime-sidecar.cjs' && basename(dirname(p)) === 'cli' && basename(dirname(dirname(p))) === 'dist';

Try / catch

try {
  acpxProviderPackageAuthority(sidecar);
} catch (err) {
  if ((err as Error).message.includes('runner_provider_package_root_incompatible')) {
    sidecar = require.resolve('acpx-provider/dist/cli/acpx-runtime-sidecar.cjs');
  } else throw err;
}

Prevention

When it happens

Trigger: Passing a sidecarScript whose basename is not acpx-runtime-sidecar.cjs, whose parent directory is not named 'cli', or whose grandparent is not named 'dist' when constructing the ACPX provider transport.

Common situations: Pointing the sidecar at a source .ts/.cjs file during dev; a custom packaging step that emits to a different directory; symlinked or pnpm-store paths breaking the dist/cli shape; hand-copying the sidecar script elsewhere.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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