{"record":{"id":"8f56ed189f5b1bad","repo":"CherryHQ/cherry-studio","slug":"agent-not-found-agentid","errorCode":null,"errorMessage":"Agent not found: ${agentId}","messagePattern":"Agent not found: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/agents/AgentJobsService.ts","lineNumber":269,"sourceCode":"        return false\n      }\n      return agentSessionService.bindTaskScheduleTx(tx, {\n        sessionId: params.sessionId,\n        taskScheduleId: params.scheduleId,\n        expectedAgentId: params.agentId\n      })\n    })\n    if (bound) agentTaskService.notifyReadModelChange([params.scheduleId])\n    return bound\n  }\n\n  // Plain Errors on purpose: no renderer branch consumes an agent/channel\n  // not-found code (the message reaches the toast through INTERNAL either\n  // way), so no AI-domain IpcError code is minted for them — unlike trigger\n  // validation, where the form must branch on the code.\n  private assertAgentExists(agentId: string): void {\n    if (!agentService.getAgent(agentId)) {\n      throw new Error(`Agent not found: ${agentId}`)\n    }\n  }\n\n  private assertChannelsBelongToAgent(agentId: string, channelIds: readonly string[]): void {\n    for (const channelId of channelIds) {\n      const channel = agentChannelService.getChannel(channelId)\n      if (!channel || channel.agentId !== agentId) {\n        throw new Error(`Channel not found: ${channelId}`)\n      }\n    }\n  }\n}\n","sourceCodeStart":251,"sourceCodeEnd":282,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/agents/AgentJobsService.ts#L251-L282","documentation":"Thrown by AgentJobsService.assertAgentExists when agentService.getAgent(agentId) returns a falsy value — i.e. no agent with the given id exists. The guard runs before binding a task schedule or trigger to an agent. The code deliberately throws a plain Error (not an IpcError with a domain code) because no renderer branch needs to branch on a not-found code; the message surfaces via the generic INTERNAL path to a toast.","triggerScenarios":"Creating or binding a task schedule/trigger for an agentId that was deleted, never existed, or whose id is stale (e.g. from an imported/duplicated config). Also when an agent is deleted while a pending schedule/trigger operation references it.","commonSituations":"User deletes an agent that still has scheduled tasks or triggers; importing a workspace/config that references agents not present in the target; race between agent deletion and a concurrent schedule operation; stale agentId cached in the UI after the agent was removed.","solutions":["Verify the agent exists before submitting the schedule/trigger: ensure the agentId is present in the current agents list and refresh if stale.","If the agent was deleted intentionally, remove or rebind the dependent schedules/triggers to a valid agent.","On the UI side, invalidate cached agent references when an agent is deleted so the user cannot submit a stale id.","If importing data, map or create the referenced agents before binding schedules."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before binding a schedule/trigger, confirm the agent exists\nif (!agentService.getAgent(agentId)) {\n  throw new Error(`Cannot bind: agent '${agentId}' does not exist`)\n}","typeGuard":"const agentExists = (id: string): boolean => agentService.getAgent(id) != null","tryCatchPattern":null,"preventionTips":["Refresh the agents list before submitting schedule/trigger forms.","On agent deletion, cascade-remove or rebind dependent schedules and triggers.","Invalidate UI-cached agent ids when an agent is deleted to prevent stale submissions.","Validate agent existence at the service boundary before persisting a schedule."],"tags":["ai","agent","validation","task-scheduling"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}