mastra-ai/mastra · error · HTTPException

Agent "${agentId}" not found

Error message

Agent "${agentId}" not found

What it means

assertChannelAgentWriteAccess checks ACL/ownership before connecting or disconnecting a channel to an agent. For unknown stored agents, connect is refused with a 404 ('Agent "X" not found'), while disconnect is allowed as orphan cleanup (the stored agent was deleted but the installation row persists) but gated on channels:write. Code-defined agents pass through because their gate is the route's auth/permission checks.

Source

Thrown at packages/server/src/server/handlers/channels.ts:84

      resource: 'agents',
      resourceId: agentId,
      action: 'edit',
      record: stored,
    });
    return;
  }

  // Not in stored-agents (or storage doesn't support it). Check the runtime
  // registry for a code-defined agent.
  const codeDefined = mastra.getAgentById(agentId);
  if (codeDefined) {
    // Code-defined agents have no owner/ACL — route's requiresAuth /
    // requiresPermission is the gate. Pass-through.
    return;
  }

  if (action === 'connect') {
    throw new HTTPException(404, { message: `Agent "${agentId}" not found` });
  }

  // Disconnect against an unknown agentId = orphan cleanup (stored agent was
  // deleted but the channel installation row is still around). Allow it, but
  // gate on channels:write so this isn't an "any authenticated user" backdoor.
  // Follow the same no-auth-configured pass-through as assertWriteAccess.
  const callerAuthorId = getCallerAuthorId(requestContext);
  if (!callerAuthorId && !requestContext.get(MASTRA_USER_KEY)) return;
  if (hasAdminBypass(requestContext, 'channels')) return;
  if (hasScopedPermission({ requestContext, resource: 'channels', action: 'write' })) return;

  throw new HTTPException(404, { message: 'Not found' });
}

// ============================================================================
// Route Definitions
// ============================================================================

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Verify the agentId exists (list stored agents or check your code-defined agents) before connecting.
  2. Create the agent first if it does not exist, then connect the channel.
  3. Re-fetch the current agent ID after any delete/recreate, rather than reusing a stored ID.
  4. For orphaned installations (agent deleted), use disconnect with channels:write permission to clean up the row.

Example fix

// before
await fetch(`/api/channels/slack/connect`, { method: 'POST', body: JSON.stringify({ agentId: 'old-agent' }) });

// after
const agents = await fetch('/api/agents').then(r => r.json());
if (!agents.some(a => a.id === agentId)) throw new Error(`Agent ${agentId} does not exist — create it first`);
Defensive patterns

Strategy: validation

Validate before calling

const agents = await listAgents();
if (!agents.some(a => a.id === agentId)) {
  throw new Error(`Agent "${agentId}" does not exist — create it before connecting a channel`);
}

Try / catch

try {
  await connectChannel(platform, agentId);
} catch (e) {
  if (e.status === 404 && e.message.startsWith('Agent "')) {
    // refresh agent list; the stored agent was likely deleted
  } else throw e;
}

Prevention

When it happens

Trigger: CONNECT_CHANNEL_ROUTE called with an agentId that is neither a stored (DB) agent nor a code-defined agent on the instance — e.g. the agent was deleted, the ID is wrong, or the agent exists on another deployment.

Common situations: Client caches an agentId after the agent was deleted; connecting a channel to a not-yet-created agent; ID casing/typo; environment mismatch (staging agentId used against production).

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/2d24820def46335e. Report an issue: GitHub.