paperclipai/paperclip · error

The Pi ACPX profile is not available

Error message

The Pi ACPX profile is not available

What it means

The transport constructor hard-disables the 'pi' agent under the ACPX provider: provider === 'acpx' && acpxAgent === 'pi' throws immediately. This profile is intentionally unavailable, so construction never succeeds for that combination.

Source

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

  #runnerRecoveryInProgress = false;
  #startupComplete = false;
  #startupFailureCode = "native_runner_process_exited";
  #controlPlaneCheckpoint:
    ((settlement: "settled" | "unsettled") => Promise<void> | void) | null =
    null;
  #controlPlaneRelease: (() => Promise<void> | void) | null = null;
  #nextTraceDebugSequence = 1;
  #traceRehydrationSpoolOverflow = false;
  #pendingTraceRehydrations: PendingTraceRehydration[] = [];
  #pendingDriverTraceInterpretations: PendingDriverTraceInterpretation[] = [];
  readonly #bridgedRuntimeInputs = new Map<string, { durableTurnId: string }>();

  constructor(readonly options: CapabilityRunnerdCodexTransportOptions) {
    if (options.adoptExistingRunner && !options.stateDirectory?.trim()) {
      throw new Error("native_adopted_runner_state_directory_required");
    }
    if (options.provider === "acpx" && options.acpxAgent === "pi") {
      throw new Error("The Pi ACPX profile is not available");
    }
    this.#failureSignal = new Promise<never>((_resolve, reject) => {
      this.#rejectFailureSignal = reject;
    });
    // Failure is also observed by request/notification paths. Register an
    // internal handler so a process exit after the owner has closed the
    // session cannot become an unhandled process-level rejection.
    void this.#failureSignal.catch(() => undefined);
    this.#ownsRoot = options.stateDirectory === undefined;
    this.#turnId = options.resumeActiveTurnId ?? "";
    this.#root =
      options.stateDirectory ??
      mkdtempSync(resolve(tmpdir(), "paperclip-runner-lab-prp-"));
    if (options.resumeDynamicTools !== undefined) {
      this.#authorizedTools = authorizedToolSetForProvider(options.provider, [
        ...options.resumeDynamicTools,
        ...codexSemanticToolSpecs(),
      ]);

View on GitHub (pinned to 01ad858492)

Solutions

  1. Choose a supported acpxAgent value (any profile other than 'pi') in the transport options.
  2. Remove or update stale configuration that still names the pi profile.
  3. Validate/sanitize the agent name against the supported set before constructing the transport.
  4. Upgrade paperclip-runner if pi support is needed, since availability may change in later versions.

Example fix

// before
new CapabilityRunnerdCodexTransport({ provider: 'acpx', acpxAgent: 'pi' });
// after
new CapabilityRunnerdCodexTransport({ provider: 'acpx', acpxAgent: 'codex' });
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED_ACPX_AGENTS = ['codex'];
if (opts.provider === 'acpx' && !SUPPORTED_ACPX_AGENTS.includes(opts.acpxAgent)) {
  throw new Error(`acpxAgent '${opts.acpxAgent}' is not supported`);
}

Type guard

const isSupportedAcpxAgent = (a: string): a is 'codex' => a !== 'pi' && SUPPORTED_ACPX_AGENTS.includes(a);

Try / catch

try {
  transport = new CapabilityRunnerdCodexTransport(options);
} catch (err) {
  if ((err as Error).message === 'The Pi ACPX profile is not available') {
    options.acpxAgent = 'codex';
    transport = new CapabilityRunnerdCodexTransport(options);
  } else throw err;
}

Prevention

When it happens

Trigger: Constructing CapabilityRunnerdCodexTransport with options.provider='acpx' and options.acpxAgent='pi'.

Common situations: Config files selecting the pi agent profile left over from an older version; user-supplied agent name passed through without allowlisting; template or docs referencing a removed profile.

Related errors


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