Stirling-Tools/Stirling-PDF · error · Error
Conversion did not return JSON content
Error message
Conversion did not return JSON content
What it means
Thrown after the polling loop when jobComplete is true but parsed is still null. This is a defensive guard: the job completed, but the result retrieval/parsing block inside the loop did not execute or failed to set parsed. Logically, if jobComplete is true, the result fetch should have run — this throw catches a logic gap.
Source
Thrown at frontend/editor/src/core/tools/pdfTextEditor/PdfTextEditor.tsx:834
data: isAxiosError(pollError)
? pollError.response?.data
: undefined,
message:
pollError instanceof Error ? pollError.message : undefined,
});
if (status === 404) {
throw new Error("Job not found on server", {
cause: pollError,
});
}
}
}
if (!jobComplete) {
throw new Error("Conversion timed out");
}
if (!parsed) {
throw new Error("Conversion did not return JSON content");
}
} else {
const content = await file.text();
const docResult = JSON.parse(content) as PdfJsonDocument;
parsed = {
...docResult,
pages: docResult.pages ?? [],
};
shouldUseLazyMode = false;
pendingJobId = null;
}
setConversionProgress(null);
if (loadRequestIdRef.current !== requestId) {
return;
}
View on GitHub (pinned to 9ef20dcab8)
Solutions
- Add logging before this throw to capture jobComplete=true, parsed=null, and the last jobStatus.
- Review the try/catch boundary: the result fetch (lines 778-805) is inside the same try that catches poll errors — a JSON.parse failure there falls through to the catch without setting parsed.
- Separate the result-fetch logic from the status-poll logic into distinct try/catch blocks.
- If reproducible, report as a logic bug in the polling loop.
Example fix
// before
if (!parsed) {
throw new Error("Conversion did not return JSON content");
}
// after
if (!parsed) {
console.error("Job marked complete but no content parsed. Last status:", lastJobStatusRef.current);
throw new Error("Conversion completed but result content was empty. Please try again.");
} Defensive patterns
Strategy: try-catch
Try / catch
// Separate result-fetch from status-poll to avoid catch-swallowing
if (jobStatus.complete && !jobStatus.error) {
jobComplete = true;
try {
const resultResponse = await apiClient.get(`/api/v1/general/job/${jobId}/result`, {
responseType: 'blob',
});
const result = JSON.parse(await resultResponse.data.text());
if (Array.isArray(result.pages)) {
parsed = result;
}
} catch (resultError) {
console.error('Result fetch failed:', resultError);
// Don't let this be swallowed by the poll catch
}
} Prevention
- Separate the result-fetch try/catch from the status-poll try/catch to prevent error swallowing.
- Add logging before this defensive guard to capture all relevant state.
- Review the polling loop flow for any path where jobComplete=true but parsed is never set.
- Report as a logic bug if this throw is ever reached in production.
When it happens
Trigger: jobStatus.complete was true but jobStatus.error was also truthy, and the error throw was caught by the catch block without setting jobComplete to false (a logic issue in the try/catch flow). Or the result fetch succeeded but JSON.parse threw, and the catch swallowed it.
Common situations: Edge case in the polling try/catch flow where a complete+error status is partially handled. JSON.parse failure on the result blob being caught by the pollError handler instead of being surfaced.
Related errors
- Failed to parse PDF JSON document
- No job ID received from server
- jobStatus.error
- PDF conversion result did not include page data. Please upda
- Conversion timed out
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/dbc233990d3ec34e.
Report an issue: GitHub.