paperclipai/paperclip · error · Error
createServerAdapter() from "${packageName}" returned an inva
Error message
createServerAdapter() from "${packageName}" returned an invalid login capability: ${err instanceof Error ? err.message : String(err)} What it means
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.
Source
Thrown at server/src/adapters/plugin-loader.ts:172
`Package "${packageName}" does not export createServerAdapter(). ` +
`Ensure the package's main entry exports a createServerAdapter function.`,
);
}
const adapterModule = createServerAdapter() as ServerAdapterModule;
if (!adapterModule || !adapterModule.type) {
throw new Error(
`createServerAdapter() from "${packageName}" returned an invalid module (missing "type").`,
);
}
// Fail closed on a malformed login capability. The validator throws a clear
// error, so the loader rejects the adapter instead of loading it with a
// partial capability.
try {
validateAdapterLoginCapability(adapterModule);
} catch (err) {
throw new Error(
`createServerAdapter() from "${packageName}" returned an invalid login capability: ` +
`${err instanceof Error ? err.message : String(err)}`,
);
}
return adapterModule;
}
export async function loadExternalAdapterPackage(
packageName: string,
localPath?: string,
): Promise<ServerAdapterModule> {
const packageDir = localPath
? path.resolve(localPath)
: path.resolve(getAdapterPluginsDir(), "node_modules", packageName);
const entryPoint = resolvePackageEntryPoint(packageDir);
const modulePath = path.resolve(packageDir, entryPoint);View on GitHub (pinned to a7e689b3c3)
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.
Example fix
// before
export function createServerAdapter() {
return {
type: "my-adapter",
login: { capabiltiy: "api-key" }, // typo, validator rejects
};
}
// after
export function createServerAdapter() {
return {
type: "my-adapter",
login: { capability: "api-key" }, // matches validateAdapterLoginCapability schema
};
} Defensive patterns
Strategy: try-catch
Validate before calling
import { validateAdapterLoginCapability } from "@paperclipai/adapter-utils";
// after createServerAdapter() returns, before handing it to the loader:
const mod = createServerAdapter();
try {
validateAdapterLoginCapability(mod);
} catch (e) {
console.error(`adapter capability invalid: ${e.message}`); // fail in dev, not at plugin load
process.exitCode = 1;
} Type guard
const isServerAdapterModule = (m: unknown): m is ServerAdapterModule => {
const mod = m as Record<string, unknown>;
return typeof mod?.type === "string";
}; Try / catch
try {
await loadExternalAdapterPackage(packageName, localPath);
} catch (e) {
if (e instanceof Error && e.message.includes("invalid login capability")) {
// surface the validator detail to the plugin author; keep the adapter disabled
logger.warn({ err: e }, `skipping adapter ${packageName}`);
return null;
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ${prefix}: the capability must be an object.
- Plugin is not ready (current status: ${plugin.status})
- Plugin worker is not running
- Plugin does not expose scoped API routes
- Plugin API route not found
AI-assisted analysis of paperclipai/paperclip@a7e689b3c3 (2026-08-21).
Data as JSON: /api/errors/9b45632e56e9642d.
Report an issue: GitHub.