{"record":{"id":"7c94c3a8a81ea3e1","repo":"jackwener/OpenCLI","slug":"aweme-id-item-id-json-stringify-publis","errorCode":null,"errorMessage":"发布成功但未返回 aweme_id/item_id: ${JSON.stringify(publishRes)}","messagePattern":"发布成功但未返回 aweme_id/item_id: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/douyin/publish.js","lineNumber":326,"sourceCode":"                },\n                anchor: {},\n                sync: {\n                    should_sync: false,\n                    sync_to_toutiao: kwargs.sync_toutiao ? 1 : 0,\n                },\n                open_platform: {},\n                assistant: { is_preview: 0, is_post_assistant: 1 },\n                declare: { user_declare_info: '{}' },\n            },\n        };\n        const publishUrl = `https://creator.douyin.com/web/api/media/aweme/create_v2/?read_aid=2906&${DEVICE_PARAMS}`;\n        process.stderr.write('  创建定时发布...\\n');\n        const publishRes = (await browserFetch(page, 'POST', publishUrl, {\n            body: publishBody,\n        }));\n        const awemeId = publishRes.aweme_id ?? publishRes.item_id;\n        if (!awemeId) {\n            throw new CommandExecutionError(`发布成功但未返回 aweme_id/item_id: ${JSON.stringify(publishRes)}`);\n        }\n        const url = `https://www.douyin.com/video/${awemeId}`;\n        const publishTimeStr = new Date(timingTs * 1000).toLocaleString('zh-CN', {\n            timeZone: 'Asia/Tokyo',\n        });\n        return [\n            {\n                status: '✅ 定时发布成功！',\n                aweme_id: awemeId,\n                url,\n                publish_time: publishTimeStr,\n            },\n        ];\n    },\n});\n","sourceCodeStart":308,"sourceCodeEnd":342,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/publish.js#L308-L342","documentation":"After submitting the scheduled publish via create_v2 (browserFetch POST to publishUrl), the command expects the response to carry aweme_id or item_id to build the video URL. If neither field is present, it throws this CommandExecutionError with the full JSON response — meaning the request likely failed or returned an error envelope despite HTTP success.","triggerScenarios":"publishRes lacks both aweme_id and item_id — e.g., Douyin returned { status_code: <nonzero>, message: ... } or a login/permission redirect body instead of a created-video object.","commonSituations":"Session/cookie expiry so create_v2 silently returns an error body; rate limiting or risk control on the account; content rejected at submit time with an error payload; API contract change renaming the id field.","solutions":["Inspect the JSON in the error message — usually a status_code/message explaining the real failure","Refresh the Douyin login session in the automation browser and retry","Check for rate limiting or account risk-control notices on the account","If the response shape changed, update the aweme_id/item_id extraction in publish.js"],"exampleFix":"// before\nconst awemeId = publishRes.aweme_id ?? publishRes.item_id;\n// after (diagnose first)\nif (publishRes.status_code && publishRes.status_code !== 0) {\n  throw new Error(`create_v2 failed: ${publishRes.status_code} ${publishRes.message}`);\n}\nconst awemeId = publishRes.aweme_id ?? publishRes.item_id ?? publishRes.data?.aweme_id;","handlingStrategy":"try-catch","validationCode":"// Probe session validity before publishing\nconst me = await fetchDouyinApi(page, '/aweme/v1/user/profile/self/');\nif (!me?.data?.user) throw new Error('Douyin session expired; re-login before publish');","typeGuard":"function hasPublishId(res) {\n  return typeof res?.aweme_id === 'string' || typeof res?.item_id === 'string';\n}","tryCatchPattern":"try {\n  const url = await douyin.publish({ title, caption });\n} catch (e) {\n  if (e instanceof CommandExecutionError && /aweme_id\\/item_id/.test(e.message)) {\n    const body = JSON.parse(e.message.match(/\\{[\\s\\S]*\\}/)?.[0] ?? '{}');\n    console.error('create_v2 said:', body.status_code, body.message); // real cause\n    // refresh session / handle rate limit, then retry\n  } else throw e;\n}","preventionTips":["Refresh Douyin login sessions before batch publishing","Honor status_code/message fields in publish responses instead of only reading ids","Throttle publish volume to avoid risk-control responses","Keep the id-extraction logic current with API changes"],"tags":["api-response","publish","session"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}