jackwener/OpenCLI · error · CommandExecutionError

${action}失败: ${JSON.stringify(error)}

Error message

${action}失败: ${JSON.stringify(error)}

What it means

thrown by throwIfImagexError when an upload/publish response contains a ResponseMetadata.Error (or top-level Error) object — i.e., the Imagex (image/video storage) API reported a structured error. The raw error object is serialized into the message.

Source

Thrown at clis/douyin/publish.js:67

    is_use_filter: 0,
    filter_id: '',
    is_cover_modify: 0,
    to_status: 0,
    cover_type: 0,
    initial_cover_uri: '',
    cut_coordinate: '',
});
function isFastDetectRetryable(error) {
    const message = error instanceof Error ? error.message : String(error);
    return message.includes('post_assistant/fast_detect') && (message.includes('Empty response') || message.includes('404') || message.includes('Not Found') || message.includes('Timeout') || message.includes('timed out') || message.includes('Failed to fetch'));
}
function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}
function throwIfImagexError(action, payload) {
    const error = payload?.ResponseMetadata?.Error ?? payload?.Error;
    if (error) {
        throw new CommandExecutionError(`${action}失败: ${JSON.stringify(error)}`);
    }
}
async function tryFastDetectFetch(page, method, url, options) {
    let lastError;
    for (let attempt = 1; attempt <= 3; attempt += 1) {
        try {
            return { ok: true, value: await browserFetch(page, method, url, options) };
        } catch (error) {
            if (!isFastDetectRetryable(error)) {
                throw error;
            }
            lastError = error;
            if (attempt < 3) {
                await sleep(500 * attempt);
            }
        }
    }
    return { ok: false, error: lastError };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the Code/Message inside the serialized error JSON — it names the exact Imagex failure (e.g. SignatureDoesNotMatch, LimitExceeded).
  2. Re-authenticate / refresh volcengine credentials used for the upload.
  3. Retry with a smaller or re-encoded video if the error indicates size/format limits.
  4. Back off and retry if the code is a rate-limit error.
  5. Check Imagex service status/quota in the volcengine console.

Example fix

// before
await publishVideo(page, kwargs);
// after: surface Code/Message instead of raw JSON
try {
    await publishVideo(page, kwargs);
} catch (e) {
    const m = /\"Code\":\s*\"([^\"]+)\"/.exec(e.message);
    if (m && m[1] === 'RequestLimitExceeded') {
        await sleep(5000);
        return publishVideo(page, kwargs);
    }
    throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// validate inputs that commonly cause Imagex errors before publishing
if (!fs.existsSync(videoPath)) throw new Error('video missing');
const size = fs.statSync(videoPath).size;
if (size > 4 * 1024 * 1024 * 1024) throw new Error('video exceeds Imagex upload limit');

Type guard

function hasImagexError(payload) {
  return payload != null && Boolean(payload?.ResponseMetadata?.Error ?? payload?.Error);
}

Try / catch

try {
  await publish({ video, title });
} catch (e) {
  const code = /\"Code\":\s*\"([^\"]+)\"/.exec(String(e.message))?.[1];
  if (['RequestLimitExceeded', 'InternalError'].includes(code)) {
    await new Promise(r => setTimeout(r, 5000));
    return publish({ video, title });
  }
  throw e;
}

Prevention

When it happens

Trigger: Any publish-step call to the Imagex API whose JSON payload includes ResponseMetadata.Error (typical volcengine/imagex error envelope: Code/Message/RequestId), caught at clis/douyin/publish.js:67.

Common situations: Expired or missing volcengine credentials; wrong bucket/service id; file too large or unsupported format upstream; rate limiting (RequestLimitExceeded); signature/auth errors from the Imagex service.

Related errors


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