paperclipai/paperclip · error · Error

${prefix}: "getCommand" must be a function.

Error message

${prefix}: "getCommand" must be a function.

What it means

Thrown by assertValidAdapterLoginCapability when loginCapability.getCommand is missing or not a function. getCommand is the required member that returns the fixed, non-secret login command string the server runs in the sandbox; the validator rejects non-function values so a static string command can never slip through.

Source

Thrown at packages/adapter-utils/src/login-capability.ts:136

  const cap = value as Record<string, unknown>;

  if (!isOneOf(ADAPTER_LOGIN_PANEL_MODES, cap.panelMode)) {
    throw new Error(
      `${prefix}: "panelMode" must be one of ${ADAPTER_LOGIN_PANEL_MODES.join(", ")}.`,
    );
  }
  if (!isOneOf(ADAPTER_LOGIN_SANDBOX_TRANSPORTS, cap.sandboxTransport)) {
    throw new Error(
      `${prefix}: "sandboxTransport" must be one of ${ADAPTER_LOGIN_SANDBOX_TRANSPORTS.join(", ")}.`,
    );
  }
  if (!isOneOf(ADAPTER_LOGIN_TIMEOUT_POLICIES, cap.timeoutPolicy)) {
    throw new Error(
      `${prefix}: "timeoutPolicy" must be one of ${ADAPTER_LOGIN_TIMEOUT_POLICIES.join(", ")}.`,
    );
  }
  if (typeof cap.getCommand !== "function") {
    throw new Error(`${prefix}: "getCommand" must be a function.`);
  }
  if (typeof cap.parsePrompt !== "function") {
    throw new Error(`${prefix}: "parsePrompt" must be a function.`);
  }
  if (cap.captureCredential !== undefined && typeof cap.captureCredential !== "function") {
    throw new Error(`${prefix}: "captureCredential" must be a function when present.`);
  }
  if (cap.onComplete !== undefined && typeof cap.onComplete !== "function") {
    throw new Error(`${prefix}: "onComplete" must be a function when present.`);
  }
  if (
    cap.completionClaim !== undefined &&
    !isOneOf(ADAPTER_LOGIN_COMPLETION_CLAIMS, cap.completionClaim)
  ) {
    throw new Error(
      `${prefix}: "completionClaim" must be one of ${ADAPTER_LOGIN_COMPLETION_CLAIMS.join(", ")} when present.`,
    );
  }

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Wrap the command in a zero-argument function: getCommand: () => "mycli login --no-browser".
  2. Keep the function free of captured secrets; it must return only the fixed command (credentials are captured later via captureCredential).
  3. Type the capability object as AdapterLoginCapability so a missing getCommand is a compile error.
  4. Add a load-time test calling validateAdapterLoginCapability on the exported module.

Example fix

// before
loginCapability = { ..., getCommand: "claude login" };

// after
loginCapability = { ..., getCommand: () => "claude login" };
Defensive patterns

Strategy: type-guard

Validate before calling

const ok = typeof (capability as { getCommand?: unknown }).getCommand === "function";

Type guard

import type { AdapterLoginCapability } from "@paperclipai/adapter-utils";

function hasGetCommand(v: unknown): v is AdapterLoginCapability {
  return typeof (v as { getCommand?: unknown })?.getCommand === "function";
}

Try / catch

try {
  assertValidAdapterLoginCapability(cap, "my-adapter");
} catch (error) {
  throw new Error(`login capability is malformed: ${String(error)}`);
}

Prevention

When it happens

Trigger: An adapter declares loginCapability = { getCommand: "paperclip login", ... } (the raw string instead of a function) or omits getCommand while declaring the rest of the capability; the loader's validateAdapterLoginCapability throws before registration completes.

Common situations: Authors storing the command directly as a string because it is constant; partial capability objects written for documentation; refactors that move command construction elsewhere and leave the field dangling.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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