lobehub/lobehub · warning · TRPCError
BAD_REQUEST
BAD_REQUEST
Error message
Topic ${topicId} has no associated agent and no agentId was provided What it means
Thrown by the agentNotify.notify mutation when a remote callback targets a topic that has no agent binding and the caller did not supply an agentId override. The notify channel writes into a topic and optionally triggers an agent run, so it must resolve exactly one agent. Without topic.agentId or input.agentId there is no agent to write on behalf of or to execute. This is a client-side contract violation (HTTP 400), not a server fault.
Source
Thrown at apps/server/src/routers/lambda/agentNotify.ts:147
);
// 1. Verify the topic exists and get its agentId + running operationId
const topic = await ctx.topicModel.findById(topicId);
if (!topic) {
throw new TRPCError({
code: 'NOT_FOUND',
message: `Topic ${topicId} not found`,
});
}
// Extract the operationId seeded by execAgent for remote hetero agents.
// Used to publish notify_update / agent_runtime_end events to the gateway WS.
const remoteOperationId = (topic.metadata as any)?.runningOperation?.operationId as
string | undefined;
const agentId = inputAgentId ?? topic.agentId;
if (!agentId) {
throw new TRPCError({
code: 'BAD_REQUEST',
message: `Topic ${topicId} has no associated agent and no agentId was provided`,
});
}
// Workspace guard: notify executes the resolved agent (directly in user
// mode, via `continue` in assistant mode) — require `use` before any write.
await assertCanUseWorkspaceAgent({
agentId,
db: ctx.serverDB,
groupId: topic.groupId,
userId: ctx.userId,
workspaceId: ctx.workspaceId,
});
/**
* Publish a stream event for remote hetero agents (openclaw / hermes).
* Fire-and-forget — stream publish failures must not break the notify response.View on GitHub (pinned to 10f24d7ade)
Solutions
- Always pass an explicit agentId in the notify input when the topic may not have one: { topicId, agentId, content }.
- Verify the topic has an agent binding before starting a remote hetero run — check topic.agentId in execAgent/dispatch before the remote callback can fire.
- Confirm the topicId is correct and belongs to an agent-backed conversation by calling topic.getById first.
- If the topic is intentionally agent-less, route the message through a different write path instead of agentNotify.
Example fix
// before — topic may have no agent
await client.agentNotify.notify.mutate({ topicId, content });
// after — pass agentId explicitly
await client.agentNotify.notify.mutate({ topicId, agentId, content }); Defensive patterns
Strategy: validation
Validate before calling
// Before calling notify, verify the topic has an agent or pass agentId explicitly
const topic = await client.topic.getById.query({ id: topicId });
if (!topic) throw new Error('Topic not found');
const resolvedAgentId = topic.agentId ?? fallbackAgentId;
if (!resolvedAgentId) throw new Error('No agent available for this topic');
await client.agentNotify.notify.mutate({ topicId, agentId: resolvedAgentId, content }); Type guard
const hasAgentBinding = (
topic: { agentId?: string | null },
inputAgentId?: string,
): topic is { agentId: string } =>
typeof topic.agentId === 'string' && topic.agentId.length > 0 || typeof inputAgentId === 'string'; Try / catch
try {
await client.agentNotify.notify.mutate({ topicId, agentId, content });
} catch (e) {
if (isTRPCError(e, 'BAD_REQUEST') && /no associated agent/.test(e.message)) {
// Supply agentId and retry, or surface to the user
}
} Prevention
- Always pass agentId explicitly in notify calls when the topic's agent binding is uncertain.
- Ensure topics created for agent runs always have agentId set at creation time.
- Validate topic.agentId before starting a remote hetero run that will call back via notify.
When it happens
Trigger: A caller invokes the trpc agentNotify.notify mutation with a topicId whose topic row has agentId=null/undefined, and omits the agentId field from the NotifySchema input. Common when an external heterogeneous agent (openclaw/hermes) calls back into a topic that was created as a bare/user-only conversation, or when the topic was migrated/corrupted and lost its agent binding.
Common situations: Using lh notify against a topic created outside an agent flow (e.g. a manually seeded topic); deleting/reassigning the agent from a topic after a run started but before the remote runtime calls back; passing the wrong topicId (typo or stale cached id) that points at a non-agent topic; integration tests that create topics without an agentId.
Related errors
AI-assisted analysis of lobehub/lobehub@10f24d7ade (2026-08-12).
Data as JSON: /api/errors/db42843c866106d3.
Report an issue: GitHub.