paperclipai/paperclip · error

session.goal.set requires an objective or active/paused stat

Error message

session.goal.set requires an objective or active/paused status

What it means

The session.goal.set command needs enough information to derive an action: either a non-empty objective ('set') or a status of 'paused' ('pause') or 'active' ('resume'). The sidecar parses these fields and throws when it cannot map them to any action.

Source

Thrown at packages/paperclip-runner/src/cli/acpx-runtime-sidecar.ts:464

  if (request.command === "session.goal.get") {
    const activeHost = requireHost();
    return observedGoalProjection(activeHost.goalCapability(), activeHost.goalSnapshot(), turnId !== null);
  }
  if (request.command === "session.goal.set") {
    const activeHost = requireHost();
    if (Object.prototype.hasOwnProperty.call(request.params, "tokenBudget")) {
      throw new Error("The negotiated ACP goal extension does not support token budget control");
    }
    const objective = text(request.params.objective).trim();
    const status = text(request.params.status).trim();
    const action = objective
      ? "set"
      : status === "paused"
        ? "pause"
        : status === "active"
          ? "resume"
          : null;
    if (!action) throw new Error("session.goal.set requires an objective or active/paused status");
    const goal = await activeHost.controlGoal(action, objective || undefined);
    return observedGoalProjection(activeHost.goalCapability(), goal, turnId !== null);
  }
  if (request.command === "session.goal.clear") {
    const activeHost = requireHost();
    await activeHost.controlGoal("clear");
    return observedGoalProjection(activeHost.goalCapability(), null, turnId !== null);
  }
  if (request.command === "session.suspend") {
    if (turnId || tools.size > 0 || inputs.size > 0) {
      throw new Error("ACPX session is not at a safe suspension point");
    }
    // Cleanup retries must be able to reach the retained host. The command is
    // still serialized, and retainActiveHostCleanup keeps admission closed
    // until one sequential close proves ownership was released.
    const activeHost = requireHost({ allowCleanupRetry: true });
    const identity = acpxProviderSessionIdentity(
      activeHost.identity(),

View on GitHub (pinned to 01ad858492)

Solutions

  1. Pass a non-empty objective string in params.objective
  2. Or pass params.status as exactly 'active' or 'paused'
  3. Normalize the caller's status enum to the ACP vocabulary before dispatch

Example fix

// before
host.dispatch({ command: 'session.goal.set', params: { status: 'running' } });
// after
host.dispatch({ command: 'session.goal.set', params: { status: 'active' } });
Defensive patterns

Strategy: validation

Validate before calling

function canDispatchGoalSet(p) { return Boolean((p.objective ?? '').trim()) || ['active','paused'].includes(p.status); }
if (!canDispatchGoalSet(params)) throw new Error('goal.set needs objective or active/paused status');

Type guard

function isValidGoalSetParams(p: { objective?: string; status?: string }): boolean {
  return Boolean(p.objective?.trim()) || p.status === 'active' || p.status === 'paused';
}

Try / catch

try { await host.dispatch({ command: 'session.goal.set', params }); }
catch (e) { if (String(e.message).includes('requires an objective')) { /* prompt user for objective or correct status */ } else throw e; }

Prevention

When it happens

Trigger: Dispatching session.goal.set where params.objective is empty/whitespace and params.status is not exactly 'paused' or 'active' (e.g. empty, 'running', 'stop').

Common situations: Passing status values from an app-level enum that doesn't match the ACP vocabulary; calling goal.set with only a token budget (also rejected) or blank fields after trimming.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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