bytedance/deer-flow · error · Error
HTTP ${response.status}
Error message
HTTP ${response.status} What it means
Thrown when the composer's `/goal` status command does a GET /api/threads/{threadId}/goal and the response is not ok. readGoalResponseError first tries to parse the Gateway's JSON `detail` field; only when the body is not JSON or lacks a string detail does it fall back to the generic `HTTP {status}`. So this message means the request failed AND the server gave no structured error detail.
Source
Thrown at frontend/src/components/workspace/input-box.tsx:893
},
[disabled, onContextChange, context, polishingInput],
);
const handleGoalCommand = useCallback(
async (command: GoalCommand): Promise<boolean> => {
const request = beginGoalRequest(goalRequestStateRef.current, threadId);
const signal = request.controller.signal;
try {
let goal: GoalState | null = null;
if (command.kind === "status") {
const response = await fetch(
`${getBackendBaseURL()}/api/threads/${encodeURIComponent(
threadId,
)}/goal`,
{ method: "GET", signal },
);
if (!response.ok) {
throw new Error(await readGoalResponseError(response));
}
goal =
((await response.json()) as { goal?: GoalState | null }).goal ??
null;
if (
!isCurrentGoalRequest(
goalRequestStateRef.current,
request,
threadId,
)
) {
return false;
}
const objective = goal?.objective;
toast.info(
objective !== undefined
? // Function replacer so a goal containing `$&`/`$1` isn't
// interpreted as a replacement pattern.View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Check the Gateway is healthy: open /health on port 8001 (or via nginx) and restart with `make stop && make dev` if needed.
- Reload the page / re-login if the auth cookie expired — 401 responses then carry a JSON detail and will show a clearer message.
- Verify the thread still exists in the sidebar; open it fresh so the URL carries the real thread id.
- If behind a custom proxy, confirm it forwards cookies and does not rewrite the /api/threads/... path.
Defensive patterns
Strategy: try-catch
Type guard
function isGoalHttpError(e: unknown): e is Error {
return e instanceof Error && /^HTTP \d{3}$/.test(e.message);
} Try / catch
try {
const r = await fetch(url, { signal });
if (!r.ok) throw new Error(await readGoalResponseError(r));
} catch (e) {
if (e instanceof DOMException && e.name === 'AbortError') return; // thread switch, ignore
toast.error(e instanceof Error ? e.message : 'goal status failed');
} Prevention
- Gate /goal commands behind a Gateway health check when the tab regains focus.
- Always pass the AbortController signal so thread switches cancel cleanly instead of surfacing stale errors.
- Keep the JSON `detail` contract on the backend so users see specific messages, not bare `HTTP {status}`.
When it happens
Trigger: Typing `/goal` in the composer for a thread whose id no longer exists on the Gateway (404), an expired/missing auth cookie (401), a CSRF or proxy failure (403), or nginx returning a non-JSON 502/504 while the Gateway is restarting. Also occurs if the thread id in the URL was hand-edited to a malformed value.
Common situations: Gateway restarted or still booting when the user runs /goal; stale browser tab pointing at a deleted thread; auth token expired mid-session; Docker stack partially up (nginx running, Gateway not).
Related errors
- Honcho request failed: POST {path}: {exc}
- mem0 request failed: {e}
- agents_api.enabled
- Failed to create agent: ${res.statusText}
- Failed to load MCP configuration
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/be230d659ba881fd.
Report an issue: GitHub.