{"record":{"id":"fa31a1e63a2916c3","repo":"CherryHQ/cherry-studio","slug":"channel-not-found-channelid","errorCode":null,"errorMessage":"Channel not found: ${channelId}","messagePattern":"Channel not found: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/agents/AgentJobsService.ts","lineNumber":277,"sourceCode":"    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":259,"sourceCodeEnd":282,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/agents/AgentJobsService.ts#L259-L282","documentation":"Thrown by AgentJobsService.assertChannelsBelongToAgent when a referenced channel either does not exist (agentChannelService.getChannel returns falsy) or exists but its agentId does not match the expected agent. Each iteration of the channel list is checked; the first invalid channel throws. Like the agent-not-found guard, this is a plain Error because no renderer branch needs a specific not-found code.","triggerScenarios":"Submitting a schedule/trigger that references a channelId which was deleted, never existed, or was reassigned to a different agent. The check is channel && channel.agentId === agentId, so a channel belonging to another agent also fails.","commonSituations":"Channel deleted while triggers still reference it; cross-agent contamination (channelId copied from a different agent's config); reassigning a channel to a new agent without updating existing triggers; stale channelId cached in the UI.","solutions":["Confirm each channelId exists and belongs to the target agent before submitting (refresh the channel list for that agent).","Remove or rebind triggers/schedules that reference deleted or reassigned channels.","Invalidate UI-cached channel references when a channel is deleted or reassigned.","Validate the channel list against the agent's current channels at form-submit time."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Confirm each channel exists and belongs to the agent before submitting\nfor (const id of channelIds) {\n  const ch = agentChannelService.getChannel(id)\n  if (!ch || ch.agentId !== agentId) {\n    throw new Error(`Channel '${id}' is missing or belongs to a different agent`)\n  }\n}","typeGuard":"const channelBelongsToAgent = (channelId: string, agentId: string): boolean => {\n  const ch = agentChannelService.getChannel(channelId)\n  return !!ch && ch.agentId === agentId\n}","tryCatchPattern":null,"preventionTips":["Refresh the channel list for the agent before submitting triggers.","On channel deletion/reassignment, cascade-update dependent triggers.","Invalidate UI-cached channel references when channels change.","Validate channel ownership at the service boundary, not only in the form."],"tags":["ai","agent","channel","validation","task-scheduling"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}