jackwener/OpenCLI · critical · CommandExecutionError
TOS init response missing UploadId: ${res.body}
Error message
TOS init response missing UploadId: ${res.body} What it means
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.
Source
Thrown at clis/douyin/_shared/tos-upload.js:206
}
catch {
return null;
}
}
// ── Phase 1: Init multipart upload ───────────────────────────────────────────
async function initMultipartUpload(tosUrl, auth, uploadHeader, userId) {
const initUrl = `${gatewayBaseUrl(tosUrl)}?uploadmode=part&phase=init`;
const res = await tosRequest({
method: 'POST',
url: initUrl,
headers: gatewayHeaders(auth, uploadHeader, userId),
});
if (res.status !== 200) {
throw new CommandExecutionError(`TOS init multipart upload failed with status ${res.status}: ${res.body}`, 'Check that TOS upload authorization is valid and not expired.');
}
const uploadId = extractUploadId(res.body);
if (!uploadId) {
throw new CommandExecutionError(`TOS init response missing UploadId: ${res.body}`);
}
return uploadId;
}
// ── Phase 2: Upload a single part ────────────────────────────────────────────
async function uploadPart(tosUrl, partNumber, uploadId, data, auth, uploadHeader, userId) {
const crc32 = crc32Hex(data);
const url = `${gatewayBaseUrl(tosUrl)}?uploadid=${encodeURIComponent(uploadId)}&part_number=${partNumber}&phase=transfer`;
const headers = {
...gatewayHeaders(auth, uploadHeader, userId),
'Content-CRC32': crc32,
'Content-Type': 'application/octet-stream',
'X-Use-Init-Upload-Optimize': '1',
'X-Use-Large-Local-Cache': '1',
};
const res = await tosRequest({ method: 'POST', url, headers, body: data });
let parsed;
try {
parsed = JSON.parse(res.body);View on GitHub (pinned to 49907e53dc)
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
Example fix
// before
const uploadId = extractUploadId(res.body); // may be undefined
// after
if (!uploadId) {
const uploadInfo = await getUploadAuthV5Credentials(page);
return retryInit(uploadInfo);
} Defensive patterns
Strategy: try-catch
Type guard
function looksLikeTosInitBody(body) {
return typeof body === 'string' && (body.includes('upload_id') || body.includes('UploadId'));
} Try / catch
try { uploadId = await initMultipartUpload(tosUrl, auth, uploadHeader, userId); }
catch (e) {
if (String(e.message).includes('missing UploadId')) {
console.error('TOS init returned unexpected body; refresh auth and retry');
uploadId = await initMultipartUpload(tosUrl, freshAuth, freshHeader, userId);
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Gateway changed response schema; request authenticated as logged-out user so a 200 HTML page is returned; CDN/proxy replaced the JSON body.
Related errors
- Cover image file not found: ${imagePath}
- ImageX upload failed with status ${res.status}: ${body}
- TOS init multipart upload failed with status ${res.status}:
- TOS upload part ${partNumber} failed with status ${res.statu
- TOS complete multipart upload failed with status ${res.statu
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/80ba283512ca43e3.
Report an issue: GitHub.