{"record":{"id":"b7ea3d2fb198b9ce","repo":"PaddlePaddle/PaddleOCR","slug":"submit-response-is-missing-jobid","errorCode":null,"errorMessage":"Submit response is missing jobId.","messagePattern":"Submit response is missing jobId\\.","errorType":"exception","errorClass":"ResponseFormatError","httpStatus":null,"severity":"error","filePath":"api_sdk/typescript/src/internal/http.ts","lineNumber":252,"sourceCode":"      // Keep raw response text.\n    }\n    if (resp.status === 401 || resp.status === 403) {\n      throw new AuthError(`Authentication failed: ${text}`);\n    } else if (resp.status === 400) {\n      throw new InvalidRequestError(`Bad request: ${text}`);\n    } else if (resp.status === 429) {\n      throw new RateLimitError(`Rate limit exceeded: ${text}`);\n    } else if (resp.status === 503 || resp.status === 504) {\n      throw new ServiceUnavailableError(resp.status, `Service unavailable: ${text}`);\n    } else {\n      throw new APIError(resp.status, text);\n    }\n  }\n}\n\nfunction requireJobId(data: SubmitResponse): string {\n  if (!data || typeof data.jobId !== \"string\" || data.jobId.length === 0) {\n    throw new ResponseFormatError(\"Submit response is missing jobId.\");\n  }\n  return data.jobId;\n}\n","sourceCodeStart":234,"sourceCodeEnd":256,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/api_sdk/typescript/src/internal/http.ts#L234-L256","documentation":"ResponseFormatError with 'Submit response is missing jobId.' comes from the requireJobId() guard: the submit call succeeded (HTTP 2xx, envelope code 0, data present) but data.jobId is not a non-empty string. The SDK requires every successful submission to return a usable jobId because all downstream operations (status polling, result fetch) key off it.","triggerScenarios":"submitJson() or submitFile() where the server's data object returns an empty jobId, a numeric/null jobId, or a renamed field (e.g. id or job_id after an API version change) — typically after backend contract drift or when pointing at a mock/stub server.","commonSituations":"Mock servers in tests returning { data: {} }; server-side A/B changes to field naming; SDK version out of sync with the deployed API; middleware stripping response fields.","solutions":["Capture the raw submit response via a custom fetchImpl to see what field the server actually returned","Align SDK and API versions — the jobId field name is part of the submit contract","If you stub the API in tests, return { code: 0, msg: \"ok\", data: { jobId: \"job-123\" } }","Retry once: a transient serialization bug can occasionally emit an empty jobId"],"exampleFix":"try {\n  const jobId = await client.submitJson(model, payload);\n} catch (e) {\n  if (e instanceof ResponseFormatError && e.message.includes(\"jobId\")) {\n    // contract violation: log raw traffic and re-submit\n    logger.error(\"Submit contract broken\", e);\n    return client.submitJson(model, payload);\n  }\n  throw e;\n}","handlingStrategy":"type-guard","validationCode":"function hasJobId(data: unknown): data is { jobId: string } {\n  return typeof data === \"object\" && data !== null\n    && typeof (data as any).jobId === \"string\" && (data as any).jobId.length > 0;\n}","typeGuard":"function isSubmitResponse(v: unknown): v is { jobId: string } {\n  return typeof v === \"object\" && v !== null && typeof (v as { jobId?: unknown }).jobId === \"string\";\n}","tryCatchPattern":"try {\n  jobId = await client.submitJson(model, payload);\n} catch (e) {\n  if (e instanceof ResponseFormatError && e.message.includes(\"jobId\")) {\n    // contract violation, retrying may help once; otherwise capture raw traffic\n    jobId = await client.submitJson(model, payload);\n  } else throw e;\n}","preventionTips":["Make mocks return { code: 0, msg: \"ok\", data: { jobId: \"job-1\" } }","Smoke-test submit → poll → result against staging after any API upgrade","Keep SDK and server versions aligned; the jobId field name is contractual"],"tags":["response-format","contract","submit","typescript"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}