paperclipai/paperclip · error · Error

${prefix}: "captureCredential" must be a function when prese

Error message

${prefix}: "captureCredential" must be a function when present.

What it means

Thrown by assertValidAdapterLoginCapability when the OPTIONAL member captureCredential is present but is not a function. captureCredential(output: string) => Buffer | null is only set by flows that print the minted credential to the terminal; the validator allows the field to be absent, but a present non-function value (boolean, string, object) means the capability shape is malformed.

Source

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

  }
  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.`,
    );
  }
}

/**
 * Validates the optional login capability of an adapter module. The function is
 * a no-op when the module declares no login capability. It throws a clear error
 * when the module declares a malformed capability, so the loader fails closed.

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Remove the captureCredential field entirely if the login flow never prints the credential to the terminal.
  2. Or provide a function (output: string) => Buffer | null that returns the raw credential bytes when present in the output, else null.
  3. Never store the credential in the capability object itself; the function returns a runtime secret, the capability data must not.
  4. Type the capability as AdapterLoginCapability so `captureCredential: true` fails to compile.

Example fix

// before
loginCapability = { ..., captureCredential: true };

// after
loginCapability = { ... };
// or, when the CLI prints the token:
// captureCredential: (output) => /^token: (\S+)$/m.exec(output)?.[1] ? Buffer.from(/^token: (\S+)$/m.exec(output)![1]) : null,
Defensive patterns

Strategy: type-guard

Validate before calling

const cap = capability as { captureCredential?: unknown };
const ok = cap.captureCredential === undefined || typeof cap.captureCredential === "function";

Type guard

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

function captureCredentialOk(v: unknown): v is AdapterLoginCapability {
  const c = v as { captureCredential?: unknown };
  return c.captureCredential === undefined || typeof c.captureCredential === "function";
}

Try / catch

try {
  assertValidAdapterLoginCapability(cap, adapterType);
} catch (error) {
  throw new Error(`optional member captureCredential malformed: ${String(error)}`);
}

Prevention

When it happens

Trigger: An adapter sets captureCredential: true (feature flag style), captureCredential: "auto", or a config object, instead of a function; validateAdapterLoginCapability throws at load time.

Common situations: Using the field as an on/off flag because other tools use booleans for optional capabilities; serializing a capability that once held a function (functions become undefined/null in JSON, but hand-written fixtures may hold junk); misunderstanding optional-vs-flag semantics.

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/bdd02249517e0ab5. Report an issue: GitHub.