paperclipai/paperclip · error · Error

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

Error message

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

What it means

Thrown by assertValidAdapterLoginCapability when the OPTIONAL member onComplete is present but not a function. onComplete(ctx: AdapterLoginCompletionContext) => Promise<void> runs after a successful login to record non-secret completion state (e.g. the stored session id); absent is allowed, present-but-not-a-function means a malformed capability.

Source

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

      `${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.
 */
export function validateAdapterLoginCapability(mod: {
  type?: unknown;

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Drop onComplete if the adapter needs no post-login bookkeeping.
  2. Or provide an async function receiving AdapterLoginCompletionContext and recording the non-secret state; it must carry no credential byte.
  3. If you meant to declare that a session id was stored, use completionClaim: "storedSessionId" instead.
  4. Type the capability as AdapterLoginCapability so non-function values fail to compile.

Example fix

// before
loginCapability = { ..., onComplete: { storedSessionId: true } };

// after
loginCapability = {
  ...,
  onComplete: async (ctx) => { if (ctx.storedSessionId) await persistSessionRef(ctx.storedSessionId); },
  completionClaim: "storedSessionId",
};
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

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

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

Try / catch

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

Prevention

When it happens

Trigger: An adapter declares onComplete: undefined-adjacent junk such as a string description, a boolean, or a plain object of handlers; validateAdapterLoginCapability rejects the module at load.

Common situations: Declaring onComplete as metadata ({ storedSessionId: true }) instead of the hook function; converting a capability to JSON and back; mixing up completionClaim (a string) and onComplete (the hook).

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