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

  1. Read the appended validator message — it names the exact field that failed; fix that field in createServerAdapter()'s return value.
  2. Align versions: rebuild/update the adapter package against the same @paperclipai/adapter-utils version the server uses.
  3. Check the adapter's tests/exports (`node -e "import('<pkg>').then(m => console.log(m.default ?? m))"`) to inspect the returned capability shape.
  4. 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

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


AI-assisted analysis of paperclipai/paperclip@a7e689b3c3 (2026-08-21). Data as JSON: /api/errors/9b45632e56e9642d. Report an issue: GitHub.