paperclipai/paperclip · error

ACPX session goal action ${action} is unavailable

Error message

ACPX session goal action ${action} is unavailable

What it means

controlGoal() on the AcpxRuntimePort validates the requested goal action against the session's declared goal capability before sending anything to the ACPX runtime. If no capability was negotiated for the session, or the capability exists but does not list the requested action (e.g. 'set', 'pause', 'resume', 'clear'), the adapter throws this error instead of dispatching an extension request the backend would reject. It is a capability gate ensuring only actions the Codex runtime advertised are attempted.

Source

Thrown at packages/paperclip-runner/src/drivers/acpx/codex-runtime-adapter.ts:1103

      return structuredClone(identity);
    },
    async getStatus() {
      return await persistedRuntimeStatus(sessionStore, handle, identity);
    },
    goalCapability() {
      return goalState.capability === null
        ? null
        : structuredClone(goalState.capability);
    },
    goalSnapshot() {
      return goalState.snapshot === null
        ? null
        : structuredClone(goalState.snapshot);
    },
    async controlGoal(action, objective) {
      const capability = goalState.capability;
      if (!capability || !capability.actions.includes(action)) {
        throw new Error(`ACPX session goal action ${action} is unavailable`);
      }
      if (!runtime.requestExtension) {
        throw new Error("ACPX runtime does not expose extension requests");
      }
      const revisionBeforeControl = goalState.revision;
      await runtime.requestExtension({
        handle,
        method: capability.controlMethod,
        params: {
          sessionId: identity.agentSessionId,
          action,
          ...(action === "set" ? { objective } : {}),
        },
        sessionMode: "persistent",
      });
      const shouldRepairMissingSetSnapshot =
        action === "set" &&
        Boolean(objective?.trim()) &&

View on GitHub (pinned to 01ad858492)

Solutions

  1. Check port.goalCapability() before calling controlGoal and only offer/execute actions present in capability.actions.
  2. If the capability is null, do not attempt goal control on this session; upgrade the ACPX/Codex runtime to a version that advertises goal support.
  3. Fix the caller's action identifier (exact match against capability.actions) and retry with a supported action.
  4. Catch the error and degrade gracefully (skip goal control UI for sessions without the capability).

Example fix

// before
await port.controlGoal("pause", undefined); // throws if 'pause' unsupported
// after
const capability = port.goalCapability();
if (capability?.actions.includes("pause")) {
  await port.controlGoal("pause", undefined);
} else {
  throw new Error("goal pause not supported by this session");
}
Defensive patterns

Strategy: validation

Validate before calling

const capability = port.goalCapability();
if (!capability || !capability.actions.includes(action)) {
  throw new Error(`action ${action} not offered by this session`);
}

Type guard

function canControlGoal(port, action) {
  const capability = port.goalCapability();
  return Array.isArray(capability?.actions) && capability.actions.includes(action);
}

Try / catch

try {
  await port.controlGoal(action, objective);
} catch (e) {
  if (String(e.message).startsWith("ACPX session goal action")) {
    disableGoalControlUi();
  } else throw e;
}

Prevention

When it happens

Trigger: Calling port.controlGoal(action, objective) where goalState.capability is null (the runtime never advertised goal support for this session) or capability.actions does not include the given action string.

Common situations: Issuing a goal 'pause'/'resume' against a Codex runtime version or session mode that only supports 'set'/'clear'; calling controlGoal on a session spawned without goal capability negotiation; a typo'd action name; reusing a goal-control helper across runtimes where only some expose goal actions.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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