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

  1. Check the Gateway is healthy: open /health on port 8001 (or via nginx) and restart with `make stop && make dev` if needed.
  2. Reload the page / re-login if the auth cookie expired — 401 responses then carry a JSON detail and will show a clearer message.
  3. Verify the thread still exists in the sidebar; open it fresh so the URL carries the real thread id.
  4. 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

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


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/be230d659ba881fd. Report an issue: GitHub.