jackwener/OpenCLI · error · CommandExecutionError
填写抖音草稿表单失败: visibility-missing
Error message
填写抖音草稿表单失败: visibility-missing
What it means
fillDraftComposer clicks a <label> whose text contains the visibility label ('公开' / '好友可见' / '仅自己可见'). If no matching label is found it throws this CommandExecutionError with reason 'visibility-missing'. The visibility section of the composer was not present or its text changed.
Source
Thrown at clis/douyin/draft.js:119
document.execCommand('selectAll', false);
document.execCommand('insertText', false, ${JSON.stringify(options.caption)});
editor.dispatchEvent(new Event('input', { bubbles: true }));
return true;
}`));
if (!captionOk) {
throw new CommandExecutionError('填写抖音草稿表单失败: caption-editor-missing');
}
}
const visibilityOk = (await page.evaluate(`() => {
const visibility = Array.from(document.querySelectorAll('label')).find(
(el) => (el.textContent || '').includes(${JSON.stringify(options.visibilityLabel)})
);
if (!(visibility instanceof HTMLElement)) return false;
visibility.click();
return true;
}`));
if (!visibilityOk) {
throw new CommandExecutionError('填写抖音草稿表单失败: visibility-missing');
}
}
/**
* Switch the composer into custom-cover mode and expose the cover input with a
* stable selector for CDP file injection.
*/
async function prepareCustomCoverInput(page) {
let lastReason = 'cover-input-missing';
const baselineCount = (await page.evaluate(`() => Array.from(document.querySelectorAll('input[type="file"]')).length`));
for (let attempt = 0; attempt < COVER_INPUT_WAIT_ATTEMPTS; attempt += 1) {
const result = (await page.evaluate(`() => {
const coverLabel = Array.from(document.querySelectorAll('label')).find(
(el) => (el.textContent || '').includes('上传新封面')
);
if (coverLabel instanceof HTMLElement) {
coverLabel.click();
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Retry once in case the section rendered late
- Inspect the composer page and update the visibility label text mapping (VISIBILITY_LABELS in clis/douyin/draft.js:12) or switch from 'label' to a broader selector like '[role="radio"]'
- Use the default --visibility public which matches the most stable '公开' label
Example fix
// before
const visibility = Array.from(document.querySelectorAll('label')).find(
(el) => (el.textContent || '').includes('好友可见')
);
// after: broader match
const visibility = Array.from(document.querySelectorAll('label,[role="radio"]')).find(
(el) => /好友可见|好友圈/.test(el.textContent || '')
); Defensive patterns
Strategy: try-catch
Try / catch
try {
await opencli.douyin.draft({ video, title, visibility: 'friends' });
} catch (e) {
if (e.message.includes('visibility-missing')) {
// retry with default visibility 'public'
await opencli.douyin.draft({ video, title, visibility: 'public' });
}
} Prevention
- Prefer the default 'public' visibility — its '公开' label is the most stable
- Keep VISIBILITY_LABELS mapping in sync with live page copy
- Fall back to default visibility instead of failing the whole draft
When it happens
Trigger: Douyin composer renders visibility options as radio buttons/custom components without a <label> containing the expected Chinese text; the visibility section is collapsed or virtualized away; the '好友可见' label copy changed (e.g. to '好友圈').
Common situations: Douyin UI update renaming visibility options; new accounts with different default visibility UI; label rendered only after scrolling the page.
Related errors
- 填写抖音草稿表单失败: title-input-missing
- 填写抖音草稿表单失败: caption-editor-missing
- 点击草稿按钮失败: ${result?.reason || 'unknown'}
- Waiting for 12306 tk auth cookie
- ChatGPT composer is not available on the current page.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5f9db3def48816df.
Report an issue: GitHub.