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
- Add ownershipModes to the oauth method, e.g. ownershipModes: ["customer"] or ["customer", "dcr"].
- Prefer building the method with the method() helper, which sets ownershipModes: ["customer", "dcr"] automatically when auth is "oauth".
- 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
- Build oauth methods only through the method() helper, which fills ownershipModes automatically.
- Avoid spreads that override the helper defaults with empty arrays.
- Type the method shape so ownershipModes is required when auth is 'oauth'.
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
- / : tool api_key requires keyPlacement
- : capture has no states
- / / : required field needs placeholder
- : invalid AppDefinition
- connector_profile_invalid
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 ? [] : fsView on GitHub (pinned to 3f1d897a7c)