{"record":{"id":"bdd02249517e0ab5","repo":"paperclipai/paperclip","slug":"prefix-capturecredential-must-be-a-function","errorCode":null,"errorMessage":"${prefix}: \"captureCredential\" must be a function when present.","messagePattern":"(.+?): \"captureCredential\" must be a function when present\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/adapter-utils/src/login-capability.ts","lineNumber":142,"sourceCode":"  }\n  if (!isOneOf(ADAPTER_LOGIN_SANDBOX_TRANSPORTS, cap.sandboxTransport)) {\n    throw new Error(\n      `${prefix}: \"sandboxTransport\" must be one of ${ADAPTER_LOGIN_SANDBOX_TRANSPORTS.join(\", \")}.`,\n    );\n  }\n  if (!isOneOf(ADAPTER_LOGIN_TIMEOUT_POLICIES, cap.timeoutPolicy)) {\n    throw new Error(\n      `${prefix}: \"timeoutPolicy\" must be one of ${ADAPTER_LOGIN_TIMEOUT_POLICIES.join(\", \")}.`,\n    );\n  }\n  if (typeof cap.getCommand !== \"function\") {\n    throw new Error(`${prefix}: \"getCommand\" must be a function.`);\n  }\n  if (typeof cap.parsePrompt !== \"function\") {\n    throw new Error(`${prefix}: \"parsePrompt\" must be a function.`);\n  }\n  if (cap.captureCredential !== undefined && typeof cap.captureCredential !== \"function\") {\n    throw new Error(`${prefix}: \"captureCredential\" must be a function when present.`);\n  }\n  if (cap.onComplete !== undefined && typeof cap.onComplete !== \"function\") {\n    throw new Error(`${prefix}: \"onComplete\" must be a function when present.`);\n  }\n  if (\n    cap.completionClaim !== undefined &&\n    !isOneOf(ADAPTER_LOGIN_COMPLETION_CLAIMS, cap.completionClaim)\n  ) {\n    throw new Error(\n      `${prefix}: \"completionClaim\" must be one of ${ADAPTER_LOGIN_COMPLETION_CLAIMS.join(\", \")} when present.`,\n    );\n  }\n}\n\n/**\n * Validates the optional login capability of an adapter module. The function is\n * a no-op when the module declares no login capability. It throws a clear error\n * when the module declares a malformed capability, so the loader fails closed.","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/packages/adapter-utils/src/login-capability.ts#L124-L160","documentation":"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.","triggerScenarios":"An adapter sets captureCredential: true (feature flag style), captureCredential: \"auto\", or a config object, instead of a function; validateAdapterLoginCapability throws at load time.","commonSituations":"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.","solutions":["Remove the captureCredential field entirely if the login flow never prints the credential to the terminal.","Or provide a function (output: string) => Buffer | null that returns the raw credential bytes when present in the output, else null.","Never store the credential in the capability object itself; the function returns a runtime secret, the capability data must not.","Type the capability as AdapterLoginCapability so `captureCredential: true` fails to compile."],"exampleFix":"// before\nloginCapability = { ..., captureCredential: true };\n\n// after\nloginCapability = { ... };\n// or, when the CLI prints the token:\n// captureCredential: (output) => /^token: (\\S+)$/m.exec(output)?.[1] ? Buffer.from(/^token: (\\S+)$/m.exec(output)![1]) : null,","handlingStrategy":"type-guard","validationCode":"const cap = capability as { captureCredential?: unknown };\nconst ok = cap.captureCredential === undefined || typeof cap.captureCredential === \"function\";","typeGuard":"import type { AdapterLoginCapability } from \"@paperclipai/adapter-utils\";\n\nfunction captureCredentialOk(v: unknown): v is AdapterLoginCapability {\n  const c = v as { captureCredential?: unknown };\n  return c.captureCredential === undefined || typeof c.captureCredential === \"function\";\n}","tryCatchPattern":"try {\n  assertValidAdapterLoginCapability(cap, adapterType);\n} catch (error) {\n  throw new Error(`optional member captureCredential malformed: ${String(error)}`);\n}","preventionTips":["Optional means omit it, not flag it with true/false.","The function returns Buffer | null and must never leak credentials into logs.","Prefer omitting captureCredential unless the CLI prints the credential to the terminal."],"tags":["adapter","login-capability","validation","typescript","credentials"],"backgroundTag":"schema-validation-failed","analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-21T17:58:32.592Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}