{"record":{"id":"9b45632e56e9642d","repo":"paperclipai/paperclip","slug":"createserveradapter-from-packagename-return","errorCode":null,"errorMessage":"createServerAdapter() from \"${packageName}\" returned an invalid login capability: ${err instanceof Error ? err.message : String(err)}","messagePattern":"createServerAdapter\\(\\) from \"(.+?)\" returned an invalid login capability: (.+?)","errorType":"http","errorClass":"Error","httpStatus":500,"severity":"error","filePath":"server/src/adapters/plugin-loader.ts","lineNumber":172,"sourceCode":"      `Package \"${packageName}\" does not export createServerAdapter(). ` +\n      `Ensure the package's main entry exports a createServerAdapter function.`,\n    );\n  }\n\n  const adapterModule = createServerAdapter() as ServerAdapterModule;\n  if (!adapterModule || !adapterModule.type) {\n    throw new Error(\n      `createServerAdapter() from \"${packageName}\" returned an invalid module (missing \"type\").`,\n    );\n  }\n\n  // Fail closed on a malformed login capability. The validator throws a clear\n  // error, so the loader rejects the adapter instead of loading it with a\n  // partial capability.\n  try {\n    validateAdapterLoginCapability(adapterModule);\n  } catch (err) {\n    throw new Error(\n      `createServerAdapter() from \"${packageName}\" returned an invalid login capability: ` +\n        `${err instanceof Error ? err.message : String(err)}`,\n    );\n  }\n\n  return adapterModule;\n}\n\nexport async function loadExternalAdapterPackage(\n  packageName: string,\n  localPath?: string,\n): Promise<ServerAdapterModule> {\n  const packageDir = localPath\n    ? path.resolve(localPath)\n    : path.resolve(getAdapterPluginsDir(), \"node_modules\", packageName);\n\n  const entryPoint = resolvePackageEntryPoint(packageDir);\n  const modulePath = path.resolve(packageDir, entryPoint);","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/server/src/adapters/plugin-loader.ts#L154-L190","documentation":"The plugin loader called the external adapter package's createServerAdapter() and got a module object, then ran validateAdapterLoginCapability() on its login capability. The validator threw (missing/mistyped fields, wrong shapes), and the loader deliberately fails closed: it rejects the adapter instead of loading it with a partial login capability. The message embeds the validator's own reason.","triggerScenarios":"loadExternalAdapterPackage / module loading of `@paperclipai/adapter-*` or a custom adapter plugin whose returned module's login capability object (fields like login flow descriptors, capability names) does not satisfy validateAdapterLoginCapability from @paperclipai/adapter-utils.","commonSituations":"Adapter written against an older adapter-utils API after a capability schema change; typos or missing required fields in the capability object; package version drift between the server's adapter-utils and the one the plugin was built with; partial refactors of an in-house adapter.","solutions":["Read the appended validator message — it names the exact field that failed; fix that field in createServerAdapter()'s return value.","Align versions: rebuild/update the adapter package against the same @paperclipai/adapter-utils version the server uses.","Check the adapter's tests/exports (`node -e \"import('<pkg>').then(m => console.log(m.default ?? m))\"`) to inspect the returned capability shape.","If the capability is intentionally absent, return the shape the validator accepts for 'no login' rather than a malformed object."],"exampleFix":"// before\nexport function createServerAdapter() {\n  return {\n    type: \"my-adapter\",\n    login: { capabiltiy: \"api-key\" }, // typo, validator rejects\n  };\n}\n\n// after\nexport function createServerAdapter() {\n  return {\n    type: \"my-adapter\",\n    login: { capability: \"api-key\" }, // matches validateAdapterLoginCapability schema\n  };\n}","handlingStrategy":"try-catch","validationCode":"import { validateAdapterLoginCapability } from \"@paperclipai/adapter-utils\";\n\n// after createServerAdapter() returns, before handing it to the loader:\nconst mod = createServerAdapter();\ntry {\n  validateAdapterLoginCapability(mod);\n} catch (e) {\n  console.error(`adapter capability invalid: ${e.message}`); // fail in dev, not at plugin load\n  process.exitCode = 1;\n}","typeGuard":"const isServerAdapterModule = (m: unknown): m is ServerAdapterModule => {\n  const mod = m as Record<string, unknown>;\n  return typeof mod?.type === \"string\";\n};","tryCatchPattern":"try {\n  await loadExternalAdapterPackage(packageName, localPath);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"invalid login capability\")) {\n    // surface the validator detail to the plugin author; keep the adapter disabled\n    logger.warn({ err: e }, `skipping adapter ${packageName}`);\n    return null;\n  }\n  throw e;\n}","preventionTips":["Pin the adapter's @paperclipai/adapter-utils version to the server's version.","Run validateAdapterLoginCapability in the adapter package's own unit tests.","Contract-test adapter modules against the server in CI before release."],"tags":["plugin","adapter","schema-validation","version-drift"],"backgroundTag":"plugin-validation-failed","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"}