Summary
Navigating directly to an agent URL that doesn't resolve — e.g. http://localhost/agents/does-not-exist — renders a completely blank page. No error, no "agent not found", no way back except the top nav. The route matches, AgentDetail.vue mounts, and then nothing is drawn at all.
AgentDetail.vue already has an error banner (v-if="error && !agent", line 25) — it just never fires, because the error never reaches the view.
Context
Hit while navigating to a stale bookmark/URL for an agent that no longer exists. The user is left staring at an empty dark canvas with no indication that anything went wrong.
Root cause — stores/agents.js::fetchAgent (line 138) swallows the failure:
async fetchAgent(name) {
try {
const response = await axios.get(`/api/agents/${name}`, { headers: authStore.authHeader })
...
return this.selectedAgent
} catch (error) {
this.error = error.message
console.error('Failed to fetch agent:', error) // <-- swallowed, returns undefined
} finally { this.loading = false }
}
It catches, logs to the console, and returns undefined. So in AgentDetail.vue::loadAgent (line 858) the catch block never runs, error.value stays '', and agent.value is undefined — making both v-if="error && !agent" and v-if="agent" false. Nothing renders. The only evidence is a console line the user never sees.
Enumeration-safety constraint (Invariant #8, #186): the backend deliberately returns a uniform 404 for both a non-existent agent and one the caller can't access — that differential is an enumeration oracle. The frontend copy must therefore not distinguish "this agent doesn't exist" from "you don't have access to it". One neutral message covers both.
Acceptance Criteria
Technical Notes
src/frontend/src/stores/agents.js — fetchAgent (line 138): the swallow. Either re-throw, or return a discriminated result; re-throwing is cleaner but requires wrapping the ~line 712 caller.
src/frontend/src/views/AgentDetail.vue — loadAgent (line 858) and the error banner (line 25). Minimal fix: distinguish 404 from other errors and render a proper not-found panel rather than the generic red banner.
src/frontend/src/router/index.js line 58 — the /agents/:name route. Alternative/complementary approach: a beforeEnter guard, though the two other agent routes (/agents/:name/workspace, /agents/:name/brain) already bail to AgentDetail, so fixing the view is the higher-leverage single point.
- Worth checking whether sibling views that fetch a named agent (
AgentWorkspace.vue, AgentBrainOrb.vue — each with their own local fetchAgent) share the blank-page failure mode. If so, note it here rather than expanding this issue's scope.
- Same swallow-and-return-undefined shape exists elsewhere in
stores/agents.js; out of scope here, but a candidate for a follow-up refactor.
Summary
Navigating directly to an agent URL that doesn't resolve — e.g.
http://localhost/agents/does-not-exist— renders a completely blank page. No error, no "agent not found", no way back except the top nav. The route matches,AgentDetail.vuemounts, and then nothing is drawn at all.AgentDetail.vuealready has an error banner (v-if="error && !agent", line 25) — it just never fires, because the error never reaches the view.Context
Hit while navigating to a stale bookmark/URL for an agent that no longer exists. The user is left staring at an empty dark canvas with no indication that anything went wrong.
Root cause —
stores/agents.js::fetchAgent(line 138) swallows the failure:It catches, logs to the console, and returns
undefined. So inAgentDetail.vue::loadAgent(line 858) thecatchblock never runs,error.valuestays'', andagent.valueisundefined— making bothv-if="error && !agent"andv-if="agent"false. Nothing renders. The only evidence is a console line the user never sees.Enumeration-safety constraint (Invariant #8, #186): the backend deliberately returns a uniform 404 for both a non-existent agent and one the caller can't access — that differential is an enumeration oracle. The frontend copy must therefore not distinguish "this agent doesn't exist" from "you don't have access to it". One neutral message covers both.
Acceptance Criteria
/agents/<unknown-name>renders a visible not-found state instead of a blank pagestores/agents.js::fetchAgentno longer silently returnsundefinedon failure — the caller can tell success from failureAgentDetail.vue(the post-stop status poll, ~line 712, which deliberately tolerates transient fetch errors) still tolerates them and does not start throwingTechnical Notes
src/frontend/src/stores/agents.js—fetchAgent(line 138): the swallow. Either re-throw, or return a discriminated result; re-throwing is cleaner but requires wrapping the ~line 712 caller.src/frontend/src/views/AgentDetail.vue—loadAgent(line 858) and the error banner (line 25). Minimal fix: distinguish 404 from other errors and render a proper not-found panel rather than the generic red banner.src/frontend/src/router/index.jsline 58 — the/agents/:nameroute. Alternative/complementary approach: abeforeEnterguard, though the two other agent routes (/agents/:name/workspace,/agents/:name/brain) already bail toAgentDetail, so fixing the view is the higher-leverage single point.AgentWorkspace.vue,AgentBrainOrb.vue— each with their own localfetchAgent) share the blank-page failure mode. If so, note it here rather than expanding this issue's scope.stores/agents.js; out of scope here, but a candidate for a follow-up refactor.