{"record":{"id":"3d2c841712b88063","repo":"paperclipai/paperclip","slug":"paperclip-runner-tool-not-advertised","errorCode":"paperclip_runner_tool_not_advertised","errorMessage":"paperclip_runner_tool_not_advertised","messagePattern":"paperclip_runner_tool_not_advertised","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/native-runtime/paperclip-runner-tool-authority.ts","lineNumber":146,"sourceCode":"          const idempotencyKey = `connection-intent:tools:${this.binding.runId}:${current.digest}`;\n          const delivered = () => this.db.select({ id: agentWakeupRequests.id }).from(agentWakeupRequests).where(and(\n            eq(agentWakeupRequests.companyId, this.binding.companyId), eq(agentWakeupRequests.idempotencyKey, idempotencyKey),\n            notInArray(agentWakeupRequests.status, [\"skipped\", \"failed\", \"cancelled\"]),\n          )).limit(1);\n          if (!(await delivered()).length) try { await this.binding.enqueueWakeup(this.binding.agentId, {\n            source: \"assignment\", triggerDetail: \"system\", reason: \"issue_assigned\",\n            payload: { issueId: this.binding.issueId, mutation: \"connection_tools_refreshed\" },\n            idempotencyKey,\n            issueStateGuard: { statuses: [\"in_progress\", \"in_review\"], assigneeAgentId: this.binding.agentId },\n            requestedByActorType: \"agent\", requestedByActorId: this.binding.agentId,\n            contextSnapshot: { issueId: this.binding.issueId, taskId: this.binding.issueId, forceFreshSession: true, wakeReason: \"issue_assigned\", source: \"connection_tools.refreshed\" },\n          }); } catch (error) { if (!(await delivered()).length) throw error; }\n          return { ...result, instruction: \"Access is already authorized. A fresh continuation with updated tools is queued. Finish independent work, then yield. Do not request authorization again.\" };\n        }\n      }\n      return result;\n    }\n    if (!IMPLEMENTED_OPERATIONS.has(call.tool)) throw new Error(\"paperclip_runner_tool_not_advertised\");\n    if (!runnerApiToolsEnabled(this.binding.companyId, this.binding.apiToolsEnabled) && [\"search_api\", \"call_api\"].includes(call.tool)) throw new Error(\"paperclip_runner_tool_not_advertised\");\n    const context = await this.#boundContext();\n    const descriptor = CAPABILITY_SEMANTIC_TOOL_CATALOG.find((candidate) => candidate.operationId === call.tool);\n    if (!descriptor || !descriptor.allowedModes.includes(\n      context.issue.workMode as \"standard\" | \"planning\" | \"ask\",\n    )) {\n      throw new Error(\"paperclip_runner_tool_mode_denied\");\n    }\n    const input = record(call.arguments);\n    switch (call.tool) {\n      case \"search_api\": return searchRunnerApi(call.arguments);\n      case \"call_api\": return this.#callApi(call.callId, call.arguments);\n      case \"get_task_context\": return {\n        company: { id: this.binding.companyId },\n        actor: redactedActor(context.actor),\n        activeTask: redactedTask(context.issue),\n        run: {\n          id: this.binding.runId,","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/native-runtime/paperclip-runner-tool-authority.ts#L128-L164","documentation":"PaperclipRunnerToolAuthority.execute validates every requested tool call against what the runner actually advertises. At paperclip-runner-tool-authority.ts:146 it throws 'paperclip_runner_tool_not_advertised' when the requested call.tool is not a connection tool (RUNTIME_CONNECTION_TOOL_DEFINITIONS) and is also not present in IMPLEMENTED_OPERATIONS — i.e. the agent invoked a tool name that is neither a runtime connection tool nor an implemented capability operation. This keeps the runner from executing tool names that were never advertised to the model.","triggerScenarios":"execute({tool, callId, arguments}) is called with a tool name that is neither in RUNTIME_CONNECTION_TOOL_DEFINITIONS nor in IMPLEMENTED_OPERATIONS — e.g. a typo'd tool name, a removed/renamed operation, a model-hallucinated tool, or a stale cached tool list referencing an old operationId.","commonSituations":"Model hallucinates a tool name not in its advertised list; server code renamed an operation while an old prompt/session still references the previous name; a plugin or adapter passes through arbitrary tool names; version skew between UI/adapter expectations and the deployed catalog.","solutions":["Check the tool name against the runner's advertised tools list (CAPABILITY_SEMANTIC_TOOL_CATALOG operationIds plus connection tools) and correct any typo or stale name.","Re-pull the current tool list for the run (toolsFor/advertised set) so the model only calls implemented operations, then retry in a fresh continuation.","If the operation should exist, add it to IMPLEMENTED_OPERATIONS and CAPABILITY_SEMANTIC_TOOL_CATALOG with an implemented handler.","If the call comes from a stale session/prompt, force a fresh session (forceFreshSession wakeup) with the updated tool catalog."],"exampleFix":"// before\nexecute({ tool: \"search_api_v2\", callId, arguments });\n// after\nexecute({ tool: \"search_api\", callId, arguments }); // name present in IMPLEMENTED_OPERATIONS","handlingStrategy":"validation","validationCode":"import { IMPLEMENTED_OPERATIONS, RUNTIME_CONNECTION_TOOL_DEFINITIONS } from \".../paperclip-runner-tool-authority\";\nfunction isCallableTool(tool: string): boolean {\n  return IMPLEMENTED_OPERATIONS.has(tool) || RUNTIME_CONNECTION_TOOL_DEFINITIONS.some((t) => t.name === tool);\n}\nif (!isCallableTool(call.tool)) throw new Error(`tool ${call.tool} is not advertised; pick one from the advertised tools list`);","typeGuard":"function isAdvertisedTool(tool: string, advertised: readonly { name: string }[]): tool is typeof advertised[number][\"name\"] {\n  return advertised.some((t) => t.name === tool);\n}","tryCatchPattern":"try {\n  return await authority.execute(call);\n} catch (err) {\n  if (err instanceof Error && err.message === \"paperclip_runner_tool_not_advertised\") {\n    return { error: \"tool_not_available\", hint: \"Re-read get_task_context/tools list and choose an advertised tool.\" };\n  }\n  throw err;\n}","preventionTips":["Always derive model-facing tool lists from the same IMPLEMENTED_OPERATIONS/catalog source the executor checks.","Validate tool names against the advertised list before dispatching calls from adapters/plugins.","Force a fresh session when the server's tool catalog changes so old tool names are not replayed.","Add a fuzz/unit test that dispatches every catalog operationId through execute()."],"tags":["tool-not-implemented","hallucinated-tool","tool-catalog","agent-runtime"],"backgroundTag":"unsupported-operation","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}