paperclipai/paperclip · error · Error
/ : tool api_key requires keyPlacement
Error message
${app.slug}/${connectionMethod.key}: tool api_key requires keyPlacement What it means
validateApp() requires that every connection method using api_key auth and a 'tool' purpose (the default) declares keyPlacement — where the API key is placed in requests (e.g. header/query). Without it, generated connection code cannot construct authenticated requests, so the definition is rejected.
Solutions
- Set keyPlacement on the api_key connection method (e.g. keyPlacement: { in: "header", name: "Authorization", format: "Bearer {apiKey}" }).
- If the key is not used for tool-call auth but for channel delivery, set purpose: "channel" to opt out of the requirement.
- Check the method() helper call for the app and pass keyPlacement through the extra object.
Example fix
// before
method("acme-key", "http", "api_key", defaults, "medium", guide)
// after
method("acme-key", "http", "api_key", defaults, "medium", guide, { keyPlacement: { in: "header", name: "X-Api-Key" } }) Defensive patterns
Strategy: validation
Validate before calling
for (const m of app.methods) {
if (m.auth === 'api_key' && !m.keyPlacement && (m.purpose ?? 'tool') === 'tool') {
throw new Error(`${app.slug}/${m.key}: set keyPlacement or purpose 'channel'`);
}
} Type guard
const hasKeyPlacement = (m) => m.auth !== 'api_key' || m.purpose === 'channel' || Boolean(m.keyPlacement);
Prevention
- When switching a method to api_key auth, add keyPlacement in the same edit.
- Document keyPlacement requirements in the method() helper JSDoc.
- Review new app PRs specifically for api_key methods missing placement.
When it happens
Trigger: For a method with auth === "api_key" and keyPlacement undefined/null, when purpose is missing (defaults to "tool") or explicitly "tool". Channel-purpose methods (purpose === "channel") are exempt.
Common situations: Adding a new API-key app and forgetting to pass keyPlacement in the method's extra options; copying an oauth method block and switching auth to "api_key" without adding the placement field; a template regression that drops keyPlacement for newly ingested providers.
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
- / : oauth requires ownershipModes
- : capture has no states
- / / : required field needs placeholder
- : invalid AppDefinition
- Enter a Cursor API key.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/c7bdc2458a085331.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/ingest-app-definitions.mjs:1586
// AI account flow; saved REST connections remain removable through Connections.
app.methods = [...methods, ...app.methods.filter(method => method.transport !== "rest_api")];
}
const validateApp = (app) => {
if (
app.schemaVersion !== 1 ||
!app.slug ||
!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.placeholderView on GitHub (pinned to 3f1d897a7c)