{"record":{"id":"26377d5c2a954cf1","repo":"paperclipai/paperclip","slug":"prefix-completionclaim-must-be-one-of-adap","errorCode":null,"errorMessage":"${prefix}: \"completionClaim\" must be one of ${ADAPTER_LOGIN_COMPLETION_CLAIMS.join(\", \")} when present.","messagePattern":"(.+?): \"completionClaim\" must be one of (.+?) when present\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/adapter-utils/src/login-capability.ts","lineNumber":151,"sourceCode":"    );\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.\n */\nexport function validateAdapterLoginCapability(mod: {\n  type?: unknown;\n  loginCapability?: unknown;\n}): void {\n  if (mod.loginCapability === undefined) return;\n  const adapterType = typeof mod.type === \"string\" && mod.type.length > 0 ? mod.type : \"unknown\";\n  assertValidAdapterLoginCapability(mod.loginCapability, adapterType);\n}","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/packages/adapter-utils/src/login-capability.ts#L133-L169","documentation":"Thrown by assertValidAdapterLoginCapability when the OPTIONAL member completionClaim is present but not one of the fixed claims (currently only \"storedSessionId\"). The claim tells the login flow what to record on success; any other string is a malformed capability and the loader fails closed.","triggerScenarios":"An adapter sets completionClaim: \"session_id\", \"apiKey\", \"stored_session_id\" (spelling variant), or a non-string; validateAdapterLoginCapability throws during module load.","commonSituations":"Authors inventing claim names to match their vendor vocabulary; adding a new claim in the adapter before the constant ADAPTER_LOGIN_COMPLETION_CLAIMS in adapter-utils supports it; leaving a placeholder string from a template.","solutions":["Use completionClaim: \"storedSessionId\" when the flow stores a session identifier on success.","Omit completionClaim entirely if the flow records nothing.","If you genuinely need a new claim, add it to ADAPTER_LOGIN_COMPLETION_CLAIMS in @paperclipai/adapter-utils (and the AdapterLoginCompletionClaim type) first, then use it.","Type the field as AdapterLoginCompletionClaim for compile-time checking."],"exampleFix":"// before\nloginCapability = { ..., completionClaim: \"session-id\" };\n\n// after\nloginCapability = { ..., completionClaim: \"storedSessionId\" };","handlingStrategy":"type-guard","validationCode":"import { ADAPTER_LOGIN_COMPLETION_CLAIMS } from \"@paperclipai/adapter-utils\";\n\nconst c = capability as { completionClaim?: unknown };\nconst ok = c.completionClaim === undefined ||\n  (ADAPTER_LOGIN_COMPLETION_CLAIMS as readonly string[]).includes(c.completionClaim as string);","typeGuard":"import { ADAPTER_LOGIN_COMPLETION_CLAIMS, type AdapterLoginCapability } from \"@paperclipai/adapter-utils\";\n\nfunction completionClaimOk(v: unknown): v is AdapterLoginCapability {\n  const c = v as { completionClaim?: unknown };\n  return c.completionClaim === undefined ||\n    (ADAPTER_LOGIN_COMPLETION_CLAIMS as readonly string[]).includes(c.completionClaim as string);\n}","tryCatchPattern":"try {\n  assertValidAdapterLoginCapability(cap, adapterType);\n} catch (error) {\n  throw new Error(`completionClaim invalid: ${String(error)}`);\n}","preventionTips":["Only \"storedSessionId\" exists today; omit the field rather than inventing claims.","Extending the claim set means changing adapter-utils first, then the adapter.","Type the field as AdapterLoginCompletionClaim."],"tags":["adapter","login-capability","validation","typescript"],"backgroundTag":"invalid-enum-value","analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-21T17:58:32.592Z","contentChangedAt":"2026-08-21T17:58:32.592Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}