Stirling-Tools/Stirling-PDF · error · Error

detail ?? `AI engine request failed: ${response.status}`

Error message

detail ?? `AI engine request failed: ${response.status}`

What it means

Thrown when the AI orchestration streaming endpoint returns a non-2xx response and no usable detail message could be extracted from the JSON body. The code attempts to read body.message/detail/error/errors[0].message; if all are absent it falls back to 'AI engine request failed: {status}'.

Source

Thrown at frontend/editor/src/proprietary/components/chat/ChatContext.tsx:615

            // non-JSON body — ignore
          }
          if (limitHandled) {
            dispatch({ type: "SET_PROGRESS", progress: null });
            dispatch({
              type: "ADD_MESSAGE",
              message: {
                id: generateId(),
                role: ChatRole.ASSISTANT,
                content: t(
                  "chat.responses.usage_limit_reached",
                  "You've reached your usage limit. Check your plan options to keep going.",
                ),
                timestamp: Date.now(),
              },
            });
            return;
          }
          throw new Error(
            detail ?? `AI engine request failed: ${response.status}`,
          );
        }

        let receivedResult = false;
        const toolsUsed: string[] = [];

        await consumeSSEStream(response, {
          onProgress: (data) => {
            if (
              data.phase === AiWorkflowPhase.EXECUTING_TOOL &&
              typeof data.tool === "string"
            ) {
              toolsUsed.push(data.tool);
            }
            const progressItem: AiWorkflowProgress = {
              phase: data.phase as AiWorkflowPhase,
              tool: data.tool,

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Check that the AI engine is running (task engine:dev, localhost:5001 health).
  2. Inspect browser DevTools Network tab for the actual status code and response body to find the real cause.
  3. Verify the auth token is valid and not expired (re-login).
  4. Check backend logs for the proxied request error.
  5. If status is 402 with a usage-limit code, ensure isPaygLimitCode handles the sentinel correctly.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const response = await fetch(url, opts);
  if (!response.ok) {
    let detail: string | undefined;
    try { detail = (await response.json())?.message; } catch { /* non-JSON */ }
    throw new Error(detail ?? `AI engine request failed: ${response.status}`);
  }
  // consume stream...
} catch (e) {
  if ((e as Error).name === "AbortError") return;
  showUserError(e as Error);
}

Prevention

When it happens

Trigger: POST to /api/v1/ai/orchestrate/stream returns 4xx/5xx (e.g. 500 internal error, 400 bad request, 401/403 auth failure that is not the 402 usage-limit case). The response body either is not JSON or lacks a message/detail/error field.

Common situations: The Python AI engine (port 5001) is down or crashed. The Java backend proxy failed to reach the engine. Authentication token expired (401). Malformed request payload (400). Engine timeout (504).

Related errors


AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13). Data as JSON: /api/errors/56bb3f06107b9c54. Report an issue: GitHub.