paperclipai/paperclip · critical
Paperclip run authentication is unavailable
Error message
Paperclip run authentication is unavailable
What it means
PaperclipRunnerToolAuthority.#callApi mints a short-lived local agent JWT (createLocalAgentJwt) before dispatching any runner API call. createLocalAgentJwt returns null when jwtConfig() cannot produce a signing configuration (missing JWT secret/keys), so the authority throws this error instead of sending an unauthenticated request. It is a fail-closed guard: no run authentication material means the runner tool cannot call the Paperclip API at all.
Source
Thrown at server/src/services/native-runtime/paperclip-runner-tool-authority.ts:249
}
case "report_progress": return this.#reportProgress(input);
case "request_human_input": return this.#requestHumanInput(input,
(await captureRunIdentity(this.db, this.binding)).context?.id ?? null);
case "create_task": return this.#createTask(input,
(await captureRunIdentity(this.db, this.binding)).context?.id ?? null);
case "set_dependencies": return this.#setDependencies(input);
default: throw new Error("paperclip_runner_tool_not_bound");
}
}
async #callApi(callId: string, value: unknown): Promise<unknown> {
const bound = await this.#boundContext();
const context = { ...this.binding, issueIdentifier: bound.issue.identifier, workMode: bound.issue.workMode };
const { input, operation } = validateRunnerApiCall(value, context);
const apiUrl = this.binding.apiUrl ?? process.env.PAPERCLIP_API_URL;
if (!apiUrl) throw new Error("Paperclip API origin is unavailable");
const token = createLocalAgentJwt(this.binding.agentId, this.binding.companyId, bound.actor.adapterType, this.binding.runId, bound.run.responsibleUserId);
if (!token) throw new Error("Paperclip run authentication is unavailable");
const execute = async () => {
const current = await this.#boundContext();
if (!runnerApiToolsEnabled(this.binding.companyId, this.binding.apiToolsEnabled)) throw new Error("paperclip_runner_tool_not_advertised");
return executeRunnerApi(input, { ...context, workMode: current.issue.workMode }, {
apiUrl, token,
beforeDispatch: async () => {
const fresh = await this.#boundContext();
if (!runnerApiToolsEnabled(this.binding.companyId, this.binding.apiToolsEnabled)) throw new Error("paperclip_runner_tool_not_advertised");
validateRunnerApiCall(input, { ...context, workMode: fresh.issue.workMode });
},
readFile: (file) => this.#readApiFile(file),
saveResponse: async (bytes, contentType) => {
const storage = this.binding.storage ?? getStorageService();
const saved = await storage.putFile({ companyId: this.binding.companyId, namespace: "runner-api", originalFilename: contentType.includes("json") ? "response.json" : "response.bin", contentType, body: bytes });
const asset = await assetService(this.db).create(this.binding.companyId, { ...saved, createdByAgentId: this.binding.agentId });
const activity = await persistActivity(this.db, { companyId: this.binding.companyId, actorType: "agent", actorId: this.binding.agentId, agentId: this.binding.agentId, runId: this.binding.runId, issueId: this.binding.issueId, action: "asset.created", entityType: "asset", entityId: asset.id, details: { source: "runner.call_api", byteSize: saved.byteSize } });
publishActivity(activity.publication);
return { artifactId: asset.id, url: `/api/assets/${asset.id}/content`, contentType, byteSize: saved.byteSize, sha256: saved.sha256 };View on GitHub (pinned to 01ad858492)
Solutions
- Configure the server's JWT signing configuration (secret/keys) so jwtConfig() returns a valid config, then restart the API server.
- Verify PAPERCLIP_API_URL (or binding.apiUrl) is also set, since the preceding check requires an API origin before token minting.
- Check server startup logs for JWT config initialization warnings and re-run the deployment/config setup steps.
- If running tests, initialize the JWT config in the test setup before exercising runner API tools.
Example fix
// before // server started with no JWT secret; createLocalAgentJwt() -> null // after // .env PAPERCLIP_JWT_SECRET=<generated-256-bit-secret> // restart server, then the runner tool can mint the local agent JWT
Defensive patterns
Strategy: try-catch
Validate before calling
import { jwtConfig } from "../agent-auth-jwt.js";
const canMint = typeof jwtConfig === "function" && jwtConfig() != null; // run before enabling runner tools
if (!canMint || !process.env.PAPERCLIP_API_URL) throw new Error("Runner API prerequisites missing: JWT config and PAPERCLIP_API_URL required"); Type guard
function hasRunAuth(t: string | null | undefined): t is string { return typeof t === "string" && t.length > 0; } Try / catch
try {
const result = await authority.callApi(input);
} catch (err) {
if (err instanceof Error && err.message === "Paperclip run authentication is unavailable") {
// surface a config error: JWT signing config missing on the server
} else throw err;
} Prevention
- Include JWT config presence in server startup health checks so misconfigured instances never serve runner tools.
- Verify JWT config in your deployment smoke test before enabling PAPERCLIP_RUNNER_API_TOOLS.
- Keep the JWT secret in managed secret storage and assert it exists during config validation.
When it happens
Trigger: An agent tool call to search_api/call_api during a native run where createLocalAgentJwt(agentId, companyId, adapterType, runId, responsibleUserId) returns null — i.e. the server's JWT signing config is absent (jwtConfig() falsy), typically because no JWT secret is configured on the instance.
Common situations: Self-hosted/dev instances started without JWT configuration in env or config file; config was reset or migrated and the signing key was dropped; running the runner authority in a test harness where jwtConfig() is not initialized.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Paperclip run authentication is unavailable
- PAPERCLIP_CLOUD_RUNTIME_IDENTITY_JWKS is not configured
- paperclip_runner_codex_permission_mode_unqualified
- Invalid configured Paperclip API origin
- OpenCode evals require exact version 1.18.17; received ${ver
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/8a561bf274c48ab6.
Report an issue: GitHub.