paperclipai/paperclip · error · Error

/ : oauth requires ownershipModes

Error message

${app.slug}/${connectionMethod.key}: oauth requires ownershipModes

What it means

validateApp() requires every oauth connection method to declare a non-empty ownershipModes array — which parties can own the token (e.g. 'customer', 'dcr'). The ownership model drives connection UI and storage, so an oauth method without it is incomplete and rejected.

Solutions

  1. Add ownershipModes to the oauth method, e.g. ownershipModes: ["customer"] or ["customer", "dcr"].
  2. Prefer building the method with the method() helper, which sets ownershipModes: ["customer", "dcr"] automatically when auth is "oauth".
  3. If truly not oauth, change auth to the correct value (e.g. "api_key") so the oauth validation branch does not apply.

Example fix

// before
{ key: "acme-mcp", transport: "mcp_remote", auth: "oauth", ownershipModes: [] }
// after
{ key: "acme-mcp", transport: "mcp_remote", auth: "oauth", ownershipModes: ["customer", "dcr"] }
Defensive patterns

Strategy: validation

Validate before calling

for (const m of app.methods) {
  if (m.auth === 'oauth' && (!Array.isArray(m.ownershipModes) || m.ownershipModes.length === 0)) {
    throw new Error(`${app.slug}/${m.key}: oauth methods need non-empty ownershipModes`);
  }
}

Type guard

const hasOwnershipModes = (m) => m.auth !== 'oauth' || (Array.isArray(m.ownershipModes) && m.ownershipModes.length > 0);

Prevention

When it happens

Trigger: A method with auth === "oauth" has ownershipModes undefined/null or ownershipModes.length === 0. This typically means the method was constructed manually instead of via the method() helper, which auto-fills ownershipModes for oauth.

Common situations: Hand-writing an oauth method object without ownershipModes; overriding the helper output with a spread that sets ownershipModes: []; refactoring that renamed the field (e.g. singular ownershipMode) leaving it empty.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/fcdc9834fa52484a. Report an issue: GitHub.

Appendix: source

Thrown at scripts/ingest-app-definitions.mjs:1593

    !app.name ||
    !Array.isArray(app.methods) ||
    app.methods.length === 0
  )
    throw new Error(`${app.slug || "unknown"}: invalid AppDefinition`);
  for (const connectionMethod of app.methods) {
    if (
      connectionMethod.auth === "api_key" &&
      !connectionMethod.keyPlacement &&
      (connectionMethod.purpose ?? "tool") !== "channel"
    )
      throw new Error(
        `${app.slug}/${connectionMethod.key}: tool api_key requires keyPlacement`,
      );
    if (
      connectionMethod.auth === "oauth" &&
      connectionMethod.ownershipModes.length === 0
    )
      throw new Error(
        `${app.slug}/${connectionMethod.key}: oauth requires ownershipModes`,
      );
    for (const connectionField of [
      ...(connectionMethod.tenantFields ?? []),
      ...(connectionMethod.extensionFields ?? []),
      ...(connectionMethod.credentialFields ?? []),
    ])
      if (
        connectionField.required &&
        connectionField.type !== "checkbox" &&
        !connectionField.placeholder
      )
        throw new Error(
          `${app.slug}/${connectionMethod.key}/${connectionField.key}: required field needs placeholder`,
        );
  }
};
const captureFiles = definitionsOnly ? [] : fs

View on GitHub (pinned to 3f1d897a7c)