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
- Check that the AI engine is running (task engine:dev, localhost:5001 health).
- Inspect browser DevTools Network tab for the actual status code and response body to find the real cause.
- Verify the auth token is valid and not expired (re-login).
- Check backend logs for the proxied request error.
- 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
- Always parse the error body for a server-provided message before falling back to a status string.
- Distinguish auth (401/403), usage-limit (402), and server (5xx) errors with distinct user guidance.
- Verify the AI engine health before allowing chat submissions.
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
- Response body is null
- Stream ended without a result
- OCR service error: ${title}
- Response is not a valid PDF. Header: "${head}"
- Failed to export PDF: ${error instanceof Error ? error.messa
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/56bb3f06107b9c54.
Report an issue: GitHub.