{"record":{"id":"d326567331437361","repo":"jackwener/OpenCLI","slug":"action-json-stringify-error","errorCode":null,"errorMessage":"${action}失败: ${JSON.stringify(error)}","messagePattern":"\\$\\{action\\}失败: \\$\\{JSON\\.stringify\\(error\\)\\}","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/douyin/publish.js","lineNumber":67,"sourceCode":"    is_use_filter: 0,\n    filter_id: '',\n    is_cover_modify: 0,\n    to_status: 0,\n    cover_type: 0,\n    initial_cover_uri: '',\n    cut_coordinate: '',\n});\nfunction isFastDetectRetryable(error) {\n    const message = error instanceof Error ? error.message : String(error);\n    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'));\n}\nfunction sleep(ms) {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction throwIfImagexError(action, payload) {\n    const error = payload?.ResponseMetadata?.Error ?? payload?.Error;\n    if (error) {\n        throw new CommandExecutionError(`${action}失败: ${JSON.stringify(error)}`);\n    }\n}\nasync function tryFastDetectFetch(page, method, url, options) {\n    let lastError;\n    for (let attempt = 1; attempt <= 3; attempt += 1) {\n        try {\n            return { ok: true, value: await browserFetch(page, method, url, options) };\n        } catch (error) {\n            if (!isFastDetectRetryable(error)) {\n                throw error;\n            }\n            lastError = error;\n            if (attempt < 3) {\n                await sleep(500 * attempt);\n            }\n        }\n    }\n    return { ok: false, error: lastError };","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/publish.js#L49-L85","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the Code/Message inside the serialized error JSON — it names the exact Imagex failure (e.g. SignatureDoesNotMatch, LimitExceeded).","Re-authenticate / refresh volcengine credentials used for the upload.","Retry with a smaller or re-encoded video if the error indicates size/format limits.","Back off and retry if the code is a rate-limit error.","Check Imagex service status/quota in the volcengine console."],"exampleFix":"// before\nawait publishVideo(page, kwargs);\n// after: surface Code/Message instead of raw JSON\ntry {\n    await publishVideo(page, kwargs);\n} catch (e) {\n    const m = /\\\"Code\\\":\\s*\\\"([^\\\"]+)\\\"/.exec(e.message);\n    if (m && m[1] === 'RequestLimitExceeded') {\n        await sleep(5000);\n        return publishVideo(page, kwargs);\n    }\n    throw e;\n}","handlingStrategy":"retry","validationCode":"// validate inputs that commonly cause Imagex errors before publishing\nif (!fs.existsSync(videoPath)) throw new Error('video missing');\nconst size = fs.statSync(videoPath).size;\nif (size > 4 * 1024 * 1024 * 1024) throw new Error('video exceeds Imagex upload limit');","typeGuard":"function hasImagexError(payload) {\n  return payload != null && Boolean(payload?.ResponseMetadata?.Error ?? payload?.Error);\n}","tryCatchPattern":"try {\n  await publish({ video, title });\n} catch (e) {\n  const code = /\\\"Code\\\":\\s*\\\"([^\\\"]+)\\\"/.exec(String(e.message))?.[1];\n  if (['RequestLimitExceeded', 'InternalError'].includes(code)) {\n    await new Promise(r => setTimeout(r, 5000));\n    return publish({ video, title });\n  }\n  throw e;\n}","preventionTips":["Parse the Code field in the message to branch on specific Imagex errors.","Refresh volcengine credentials before long publish pipelines.","Rate-limit uploads to avoid RequestLimitExceeded.","Verify bucket/service quotas in the volcengine console."],"tags":["douyin","upload","imagex","api-error"],"backgroundTag":"cloud-api-error-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}