{"record":{"id":"d68267b707a22a36","repo":"paperclipai/paperclip","slug":"paperclip-runner-tool-mode-denied","errorCode":"paperclip_runner_tool_mode_denied","errorMessage":"paperclip_runner_tool_mode_denied","messagePattern":"paperclip_runner_tool_mode_denied","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/native-runtime/paperclip-runner-tool-authority.ts","lineNumber":343,"sourceCode":"        cursor:\n          input.cursor === null || input.cursor === undefined\n            ? null\n            : requiredString(input.cursor),\n      });\n    }\n    if (call.tool === REUSE_CHAT_ATTACHMENT_TOOL_NAME) {\n      return this.#reuseChatAttachment(input);\n    }\n    const descriptor = CAPABILITY_SEMANTIC_TOOL_CATALOG.find(\n      (candidate) => candidate.operationId === call.tool,\n    );\n    if (\n      !descriptor ||\n      !descriptor.allowedModes.includes(\n        context.issue.workMode as \"standard\" | \"planning\" | \"ask\",\n      )\n    ) {\n      throw new Error(\"paperclip_runner_tool_mode_denied\");\n    }\n    switch (call.tool) {\n      case \"create_skill\": {\n        const apiUrl = this.binding.apiUrl ?? process.env.PAPERCLIP_API_URL;\n        const token = createLocalAgentJwt(this.binding.agentId, this.binding.companyId, context.actor.adapterType, this.binding.runId, context.run.responsibleUserId);\n        if (!apiUrl || !token) throw new Error(\"Skill tool authentication is unavailable\");\n        return callCreateSkillTool({ arguments: input, apiUrl, token, companyId: this.binding.companyId });\n      }\n      case \"create_project\":\n      case \"list_project_repositories\":\n      case \"list_projects\": {\n        const apiUrl = this.binding.apiUrl ?? process.env.PAPERCLIP_API_URL;\n        const token = createLocalAgentJwt(this.binding.agentId, this.binding.companyId, context.actor.adapterType, this.binding.runId, context.run.responsibleUserId);\n        if (!apiUrl || !token) throw new Error(\"Project tool authentication is unavailable\");\n        return callProjectTool({ name: call.tool, arguments: input, apiUrl, token,\n          companyId: this.binding.companyId, issueId: this.binding.issueId, agentId: this.binding.agentId,\n          conversation: Boolean(context.issue.conversationAgentId) });\n      }","sourceCodeStart":325,"sourceCodeEnd":361,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/native-runtime/paperclip-runner-tool-authority.ts#L325-L361","documentation":"Runner tools are gated by the issue's work mode. Each tool descriptor declares allowedModes (e.g., standard/planning/ask); before executing, the authority checks the current issue.workMode against the descriptor. This error means the requested tool is not permitted in the issue's current work mode (e.g., a mutating tool during an 'ask' session).","triggerScenarios":"execute() looks up the tool descriptor and either finds none, or descriptor.allowedModes does not include context.issue.workMode cast as \"standard\" | \"planning\" | \"ask\" — e.g., calling create_skill or create_project while the issue is in 'ask' or 'planning' mode.","commonSituations":"User switched the issue to 'ask' mode but the agent still attempts mutating tools; running in 'planning' mode where only read-only tools are allowed; a tool registered without the current mode in its allowedModes list after a mode introduction; stale UI mode while the agent loop keeps running old tool calls.","solutions":["Switch the issue's work mode to one included in the tool's allowedModes (e.g., standard) before invoking the tool.","Ask the agent to skip the tool call in the current mode, or restrict the tool from the model's toolset for that mode.","Update the tool descriptor's allowedModes if the tool should legitimately run in the new mode.","Verify issue.workMode value is a recognized mode and the descriptor lookup uses the right tool name."],"exampleFix":"// before\nawait patchIssue(issueId, { workMode: \"ask\" });\nawait runner.execute({ tool: \"create_skill\", arguments }); // denied in ask mode\n// after\nawait patchIssue(issueId, { workMode: \"standard\" });\nawait runner.execute({ tool: \"create_skill\", arguments });","handlingStrategy":"validation","validationCode":"function toolAllowedInMode(descriptor, workMode) {\n  return !!descriptor && descriptor.allowedModes.includes(workMode);\n}\n// before execute: if (!toolAllowedInMode(descriptors[call.tool], issue.workMode)) skipTool(call);","typeGuard":"const isToolAllowed = (descriptor, workMode) => !!descriptor && descriptor.allowedModes.includes(workMode);","tryCatchPattern":"try {\n  return await authority.execute(call);\n} catch (e) {\n  if (e.message === \"paperclip_runner_tool_mode_denied\") {\n    return respondSkipped(`Tool ${call.tool} is not available in work mode ${context.issue.workMode}`);\n  }\n  throw e;\n}","preventionTips":["Filter the model's toolset to descriptors whose allowedModes include the current issue.workMode.","Surface mode changes (ask/planning/standard) to the agent loop promptly.","When adding modes or tools, update descriptor allowedModes in the same change.","Pre-check issue.workMode against the descriptor before invoking mutating tools."],"tags":["permissions","work-mode","runner-tools","policy"],"backgroundTag":"permission-denied","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}