paperclipai/paperclip · error
Enter a Cursor API key.
Error message
Enter a Cursor API key.
What it means
preparedConfig() requires an API key for the cursor_cloud and hermes_gateway adapter types: if apiKey is blank AND no organization secret binding (selectedBinding) is chosen, it throws. For cursor_cloud the message is specifically "Enter a Cursor API key." (for hermes_gateway it names the env key instead). The key may be entered directly or delegated to an org secret binding, but one of the two must be present.
Solutions
- Paste a valid Cursor API key into the API key field.
- Or select an existing organization secret binding via selectedBinding instead of a raw key.
- If no org secret exists, create one for the Cursor key, then select it.
- Re-check the field after switching adapter types — the key may have been cleared.
Example fix
// before: relying on an unset default
apiKey: "",
selectedBinding: null
// after: bind the org secret (or paste the key)
selectedBinding: { id: "org-secret-cursor", label: "CURSOR_API_KEY" } Defensive patterns
Strategy: validation
Validate before calling
const keyOk =
!("cursor_cloud" === adapterType) ||
apiKey.trim().length > 0 ||
selectedBinding != null;
if (!keyOk) showError("Enter a Cursor API key."); Type guard
const hasCredential =
(apiKey: string, binding: { id: string } | null): boolean =>
apiKey.trim().length > 0 || binding != null; Try / catch
try {
const cfg = preparedConfig();
submit(cfg);
} catch (e) {
if (e instanceof Error && e.message.includes("API key")) {
setKeyFieldError(e.message);
} else throw e;
} Prevention
- Provide either a raw API key or an org secret binding — at least one.
- Re-verify credentials after switching adapter types mid-flow.
- Provision org secrets before rolling out adapter setup to users.
- Trim pasted keys to avoid whitespace-only values.
When it happens
Trigger: Submitting setup with adapterType "cursor_cloud", the API key field empty, and no org secret selected from selectedBinding.
Common situations: User expects the key to come from an environment/organization default but has not selected a binding; key was pasted with only whitespace; switching adapter types reset the field; first-time setup with no org secrets configured yet.
Understand the failure class
Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.
Related errors
- Enter a GitHub repository URL.
- / : tool api_key requires keyPlacement
- Choose or enter a model in provider/model format.
- Enter the Hermes API base URL.
- Enter the Kimi API model name.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-10).
Data as JSON: /api/errors/c6202df2bd88eaff.
Report an issue: GitHub.
Appendix: source
Thrown at ui/src/components/new-agent/NewAgentSetup.tsx:394
: {}),
};
}
return config;
}
function preparedConfig(nextConnection = connection) {
if (multiProvider && (!model.trim() || !model.includes("/")))
throw new Error("Choose or enter a model in provider/model format.");
if (
adapterType === "cursor_cloud" &&
!/^https:\/\/github\.com\/[^/]+\/[^/]+/.test(repository.trim())
)
throw new Error("Enter a GitHub repository URL.");
if (
["cursor_cloud", "hermes_gateway"].includes(adapterType) &&
!apiKey.trim() &&
!selectedBinding
)
throw new Error(
adapterType === "cursor_cloud"
? "Enter a Cursor API key."
: `Enter ${envKey} or select an organization secret.`,
);
if (adapterType === "hermes_gateway") {
try {
const url = new URL(gatewayUrl.trim());
if (!["https:", "http:"].includes(url.protocol)) throw new Error();
} catch {
throw new Error("Enter the Hermes API base URL.");
}
}
if (usingKimiApi && !kimiModel.trim())
throw new Error("Enter the Kimi API model name.");
return buildConfig(nextConnection);
}
function pendingCredentials(nextConnection = connection) {
if (aiBinding || nextConnection?.aiConnection) return {};View on GitHub (pinned to 3f1d897a7c)