{"record":{"id":"5a7f3bbac7f8c186","repo":"paperclipai/paperclip","slug":"prefix-parseprompt-must-be-a-function","errorCode":null,"errorMessage":"${prefix}: \"parsePrompt\" must be a function.","messagePattern":"(.+?): \"parsePrompt\" must be a function\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/adapter-utils/src/login-capability.ts","lineNumber":139,"sourceCode":"    throw new Error(\n      `${prefix}: \"panelMode\" must be one of ${ADAPTER_LOGIN_PANEL_MODES.join(\", \")}.`,\n    );\n  }\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/**","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/packages/adapter-utils/src/login-capability.ts#L121-L157","documentation":"Thrown by assertValidAdapterLoginCapability when loginCapability.parsePrompt is missing or not a function. parsePrompt(output: string) => AdapterLoginPrompt | null is required: the server feeds it incremental login output and it must return the authorization URL (and code) once a prompt appears, or null while waiting. A missing parser means the login flow could never surface the URL to the user.","triggerScenarios":"An adapter declares a loginCapability with getCommand but no parsePrompt; or sets parsePrompt to an object/regex instead of a function; validateAdapterLoginCapability rejects it at load.","commonSituations":"Adapters that only need to run a command and forget the server must extract the auth URL from output; parse logic kept as data (a regex pattern string) instead of wrapped in a function; partial implementations shipped by mistake.","solutions":["Implement parsePrompt as a function returning { url } (plus optional code) when the output contains a prompt, else null.","Keep every input byte out of the returned prompt and out of thrown errors (the contract forbids echoing sandbox output).","Type the capability as AdapterLoginCapability so the missing member fails to compile.","Test parsePrompt against a recorded login-output fixture in the adapter package."],"exampleFix":"// before\nloginCapability = { ..., getCommand: () => \"claude login\" };\n\n// after\nloginCapability = {\n  ...,\n  parsePrompt: (output) => {\n    const m = output.match(/https:\\/\\/example\\.com\\/auth\\?code=\\S+/);\n    return m ? { url: m[0] } : null;\n  },\n};","handlingStrategy":"type-guard","validationCode":"const ok = typeof (capability as { parsePrompt?: unknown }).parsePrompt === \"function\";","typeGuard":"import type { AdapterLoginCapability } from \"@paperclipai/adapter-utils\";\n\nfunction hasParsePrompt(v: unknown): v is AdapterLoginCapability {\n  return typeof (v as { parsePrompt?: unknown })?.parsePrompt === \"function\";\n}","tryCatchPattern":"try {\n  assertValidAdapterLoginCapability(cap, adapterType);\n} catch (error) {\n  failAdapterLoad(error); // never register a capability without a prompt parser\n}","preventionTips":["parsePrompt must return { url, code? } or null — never throw on partial output.","Test the parser against recorded login output fixtures.","Type the capability object as AdapterLoginCapability so the member cannot be omitted."],"tags":["adapter","login-capability","validation","typescript"],"backgroundTag":"schema-validation-failed","analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-21T17:58:32.592Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}