{"record":{"id":"80ba283512ca43e3","repo":"jackwener/OpenCLI","slug":"tos-init-response-missing-uploadid-res-body","errorCode":null,"errorMessage":"TOS init response missing UploadId: ${res.body}","messagePattern":"TOS init response missing UploadId: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"critical","filePath":"clis/douyin/_shared/tos-upload.js","lineNumber":206,"sourceCode":"    }\n    catch {\n        return null;\n    }\n}\n// ── Phase 1: Init multipart upload ───────────────────────────────────────────\nasync function initMultipartUpload(tosUrl, auth, uploadHeader, userId) {\n    const initUrl = `${gatewayBaseUrl(tosUrl)}?uploadmode=part&phase=init`;\n    const res = await tosRequest({\n        method: 'POST',\n        url: initUrl,\n        headers: gatewayHeaders(auth, uploadHeader, userId),\n    });\n    if (res.status !== 200) {\n        throw new CommandExecutionError(`TOS init multipart upload failed with status ${res.status}: ${res.body}`, 'Check that TOS upload authorization is valid and not expired.');\n    }\n    const uploadId = extractUploadId(res.body);\n    if (!uploadId) {\n        throw new CommandExecutionError(`TOS init response missing UploadId: ${res.body}`);\n    }\n    return uploadId;\n}\n// ── Phase 2: Upload a single part ────────────────────────────────────────────\nasync function uploadPart(tosUrl, partNumber, uploadId, data, auth, uploadHeader, userId) {\n    const crc32 = crc32Hex(data);\n    const url = `${gatewayBaseUrl(tosUrl)}?uploadid=${encodeURIComponent(uploadId)}&part_number=${partNumber}&phase=transfer`;\n    const headers = {\n        ...gatewayHeaders(auth, uploadHeader, userId),\n        'Content-CRC32': crc32,\n        'Content-Type': 'application/octet-stream',\n        'X-Use-Init-Upload-Optimize': '1',\n        'X-Use-Large-Local-Cache': '1',\n    };\n    const res = await tosRequest({ method: 'POST', url, headers, body: data });\n    let parsed;\n    try {\n        parsed = JSON.parse(res.body);","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/_shared/tos-upload.js#L188-L224","documentation":"After a 200 init response, initMultipartUpload extracts the UploadId via extractUploadId; this CommandExecutionError is thrown when the response body contains no UploadId. Without an uploadId the multipart session cannot proceed.","triggerScenarios":"The TOS init endpoint returned HTTP 200 but a body in an unexpected shape (HTML error page, JSON without upload_id, auth-warned payload), so extractUploadId finds nothing.","commonSituations":"Gateway changed response schema; request authenticated as logged-out user so a 200 HTML page is returned; CDN/proxy replaced the JSON body.","solutions":["Log the response body from the error message to see what was actually returned","Re-acquire upload authorization and retry (200-but-invalid usually means auth/session issue)","Check for Douyin/TOS API schema changes and update extractUploadId parsing","Bypass proxies/CDN that may rewrite the response"],"exampleFix":"// before\nconst uploadId = extractUploadId(res.body); // may be undefined\n// after\nif (!uploadId) {\n  const uploadInfo = await getUploadAuthV5Credentials(page);\n  return retryInit(uploadInfo);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function looksLikeTosInitBody(body) {\n  return typeof body === 'string' && (body.includes('upload_id') || body.includes('UploadId'));\n}","tryCatchPattern":"try { uploadId = await initMultipartUpload(tosUrl, auth, uploadHeader, userId); }\ncatch (e) {\n  if (String(e.message).includes('missing UploadId')) {\n    console.error('TOS init returned unexpected body; refresh auth and retry');\n    uploadId = await initMultipartUpload(tosUrl, freshAuth, freshHeader, userId);\n  } else throw e;\n}","preventionTips":["Refresh authorization right before init so a 200-invalid-body auth page is unlikely","Pin/monitor Douyin gateway response schema; add a parser test with a real captured body","Avoid proxies that rewrite JSON responses","Log raw bodies of gateway calls in debug mode"],"tags":["upload","response-parsing","douyin"],"backgroundTag":"upload-id-missing","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}