jackwener/OpenCLI · critical · CommandExecutionError

TOS upload part ${partNumber} failed with status ${res.statu

Error message

TOS upload part ${partNumber} failed with status ${res.status}: ${res.body}

What it means

uploadPart PUTs one part of the file to TOS and expects HTTP 200 with parsed.code === 2000 (application-level success). This CommandExecutionError is thrown when either the HTTP status or the JSON code indicates the part upload was rejected.

Source

Thrown at clis/douyin/_shared/tos-upload.js:230

    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);
    }
    catch {
        parsed = null;
    }
    if (res.status !== 200 || parsed?.code !== 2000) {
        throw new CommandExecutionError(`TOS upload part ${partNumber} failed with status ${res.status}: ${res.body}`, 'Check that TOS upload authorization is valid and not expired.');
    }
    return parsed?.data?.crc32 || crc32;
}
// ── Phase 3: Complete multipart upload ───────────────────────────────────────
async function completeMultipartUpload(tosUrl, uploadId, parts, auth, uploadHeader, userId) {
    const url = `${gatewayBaseUrl(tosUrl)}?uploadmode=part&phase=finish&uploadid=${encodeURIComponent(uploadId)}`;
    const body = parts
        .sort((a, b) => a.partNumber - b.partNumber)
        .map(p => `${p.partNumber}:${p.crc32}`)
        .join(',');
    const res = await tosRequest({
        method: 'POST',
        url,
        headers: gatewayHeaders(auth, uploadHeader, userId),
        body,
    });
    let parsed;
    try {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-fetch upload authorization and restart/resume the upload
  2. Retry the failing part with backoff (transient network errors)
  3. Check res.body for server-side reason (throttle, auth, signature)
  4. Verify the part buffer and crc32Hex computation are correct and the file wasn't modified mid-upload

Example fix

// before
await uploadPart(tosUrl, partNumber, uploadId, buffer, auth, uploadHeader, userId);
// after
for (let i = 0; i < 3; i++) {
  try { return await uploadPart(tosUrl, partNumber, uploadId, buffer, auth, uploadHeader, userId); }
  catch (e) { await sleep(1000 * 2 ** i); }
}
throw new Error('part upload failed after retries');
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check upload info freshness before the part loop
if (!uploadInfo || !uploadInfo.auth) throw new Error('missing TOS auth before part upload');

Try / catch

try { await uploadPart(tosUrl, partNumber, uploadId, buffer, auth, uploadHeader, userId); }
catch (e) {
  if (String(e.message).startsWith('TOS upload part')) {
    await sleep(2000);
    await uploadPart(tosUrl, partNumber, uploadId, buffer, auth, uploadHeader, userId); // resume state keeps progress
  } else throw e;
}

Prevention

When it happens

Trigger: tosUpload loop -> uploadPart with a part buffer; server returns non-200, or 200 with body code != 2000 — expired auth mid-upload, wrong CRC32 handling, throttling, or part-data corruption.

Common situations: Long uploads where the TOS auth expires between init and later parts; network interruptions; resuming with a stale uploadId after server-side cleanup.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/187bc58886db2c68. Report an issue: GitHub.