{"record":{"id":"19f9c4b01ab5ed16","repo":"Stirling-Tools/Stirling-PDF","slug":"no-job-id-received-from-server","errorCode":null,"errorMessage":"No job ID received from server","messagePattern":"No job ID received from server","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/core/tools/pdfTextEditor/PdfTextEditor.tsx","lineNumber":723,"sourceCode":"\n          const formData = new FormData();\n          formData.append(\"fileInput\", file);\n\n          console.log(\"Sending conversion request with async=true\");\n          const response = await apiClient.post(\n            `${CONVERSION_ENDPOINTS[\"pdf-text-editor\"]}?async=true&lightweight=true`,\n            formData,\n            {\n              responseType: \"json\",\n            },\n          );\n\n          console.log(\"Conversion response:\", response.data);\n          const jobId = response.data.jobId;\n\n          if (!jobId) {\n            console.error(\"No job ID in response:\", response.data);\n            throw new Error(\"No job ID received from server\");\n          }\n\n          pendingJobId = jobId;\n          console.log(\"Got job ID:\", jobId);\n          setConversionProgress({\n            percent: 3,\n            stage: \"processing\",\n            message: \"Starting conversion...\",\n          });\n\n          let jobComplete = false;\n          let attempts = 0;\n          const maxAttempts = 600;\n          let pollDelay = 500;\n\n          while (!jobComplete && attempts < maxAttempts) {\n            await new Promise((resolve) => setTimeout(resolve, pollDelay));\n            attempts += 1;","sourceCodeStart":705,"sourceCodeEnd":741,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/core/tools/pdfTextEditor/PdfTextEditor.tsx#L705-L741","documentation":"Thrown in PdfTextEditor's async conversion flow when the POST to the conversion endpoint (?async=true&lightweight=true) returns a JSON response without a jobId field. The async conversion protocol requires the server to immediately return { jobId: string } so the client can poll for completion. Without it, the polling loop cannot start.","triggerScenarios":"The server version doesn't support the async=true query parameter and returned a synchronous response (the full PDF JSON directly). Or the server returned an error object without a jobId field. Or the endpoint returned an unexpected schema.","commonSituations":"Server/client version mismatch — client expects async protocol but server is older and only supports synchronous. Server returned { error: '...' } or { status: 'failed' } without a jobId. Network proxy stripped or modified the response.","solutions":["Check if response.data contains the full conversion result (pages array) — if so, the server doesn't support async mode; fall back to synchronous parsing.","Verify server version supports async conversion (check /api/v1/info or release notes).","Log the full response.data to diagnose the unexpected shape.","Fall back to synchronous mode (remove ?async=true) if jobId is absent but response looks like valid conversion data."],"exampleFix":"// before\nconst jobId = response.data.jobId;\nif (!jobId) {\n  throw new Error(\"No job ID received from server\");\n}\n\n// after\nconst jobId = response.data.jobId;\nif (!jobId) {\n  if (Array.isArray(response.data.pages)) {\n    // Server doesn't support async — use synchronous result directly\n    parsed = response.data as PdfJsonDocument;\n    pendingJobId = null;\n  } else {\n    throw new Error(`Unexpected server response: ${JSON.stringify(response.data).slice(0, 200)}`);\n  }\n}","handlingStrategy":"validation","validationCode":"// Check if response contains jobId OR a synchronous result\nconst data = response.data;\nif (data.jobId) {\n  // async path — proceed with polling\n} else if (Array.isArray(data.pages)) {\n  // sync path — server doesn't support async, use result directly\n  parsed = data as PdfJsonDocument;\n} else {\n  throw new Error(`Unexpected conversion response: ${JSON.stringify(data).slice(0, 200)}`);\n}","typeGuard":"function hasJobId(data: unknown): data is { jobId: string } {\n  return typeof data === 'object' && data !== null && typeof (data as any).jobId === 'string';\n}","tryCatchPattern":"try {\n  const response = await apiClient.post(endpoint, formData, { responseType: 'json' });\n  if (!response.data.jobId && !Array.isArray(response.data.pages)) {\n    throw new Error('Server returned unexpected conversion response.');\n  }\n} catch (error) {\n  setErrorMessage(`Failed to start conversion: ${error instanceof Error ? error.message : 'unknown'}`);\n}","preventionTips":["Verify server version supports async conversion before relying on the jobId protocol.","Handle both async (jobId) and synchronous (pages) response shapes.","Log the full response data when jobId is missing to diagnose schema mismatches.","Fall back to synchronous mode if the server doesn't return a jobId."],"tags":["pdf-text-editor","async","api","conversion","version-mismatch"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}