{"record":{"id":"2bfe958fbde1f171","repo":"jackwener/OpenCLI","slug":"title-input-missing","errorCode":null,"errorMessage":"填写抖音草稿表单失败: title-input-missing","messagePattern":"填写抖音草稿表单失败: title-input-missing","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/douyin/draft.js","lineNumber":93,"sourceCode":"    } else {\n      titleInput.focus();\n      titleInput.value = ${JSON.stringify(options.title)};\n      titleInput.dispatchEvent(new Event('input', { bubbles: true }));\n      titleInput.dispatchEvent(new Event('change', { bubbles: true }));\n    }\n    if (props?.onBlur) {\n      props.onBlur({\n        target: titleInput,\n        currentTarget: titleInput,\n        relatedTarget: null,\n      });\n    } else {\n      titleInput.dispatchEvent(new Event('blur', { bubbles: true }));\n    }\n    return true;\n  }`));\n    if (!titleOk) {\n        throw new CommandExecutionError('填写抖音草稿表单失败: title-input-missing');\n    }\n    if (options.caption) {\n        const captionOk = (await page.evaluate(`() => {\n      const editor = document.querySelector('[contenteditable=\"true\"]');\n      if (!(editor instanceof HTMLElement)) return false;\n      editor.focus();\n      editor.textContent = '';\n      document.execCommand('selectAll', false);\n      document.execCommand('insertText', false, ${JSON.stringify(options.caption)});\n      editor.dispatchEvent(new Event('input', { bubbles: true }));\n      return true;\n    }`));\n        if (!captionOk) {\n            throw new CommandExecutionError('填写抖音草稿表单失败: caption-editor-missing');\n        }\n    }\n    const visibilityOk = (await page.evaluate(`() => {\n    const visibility = Array.from(document.querySelectorAll('label')).find(","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/draft.js#L75-L111","documentation":"fillDraftComposer looks for an <input> whose placeholder contains '填写作品标题' to type the video title. If no such input exists on the composer page it throws this CommandExecutionError with reason 'title-input-missing'. The composer was detected (waitForDraftComposer passed) but the title field cannot be found at fill time.","triggerScenarios":"Douyin rendered a different composer variant (A/B test) without the '填写作品标题' placeholder; a coach-mark/modal covers or replaces the form between the ready check and the fill step; DOM re-render removed the input before evaluate ran.","commonSituations":"Douyin UI update changing the placeholder text; intermittent modal ('我知道了' tips) appearing after the ready check; running against a regional/beta version of creator center.","solutions":["Re-run the command once — transient modals or re-renders often resolve it (dismissKnownModals runs again on retry)","Screenshot/inspect the page at failure and check whether the title input's placeholder text changed; update the selector in clis/douyin/draft.js:64","Ensure no manual interference (other tabs/scripts) mutating the page during the run"],"exampleFix":"// before\n(el) => (el.placeholder || '').includes('填写作品标题')\n// after: accept known variants\nconst TITLE_PLACEHOLDERS = ['填写作品标题', '填写标题', '标题'];\n(el) => TITLE_PLACEHOLDERS.some((p) => (el.placeholder || '').includes(p))","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await opencli.douyin.draft({ video, title });\n} catch (e) {\n  if (e.message.includes('title-input-missing')) {\n    // capture a screenshot of the composer, compare placeholder text, retry once\n  }\n}","preventionTips":["Retry transient selector failures once before surfacing","Keep selectors tolerant of placeholder-text variants","Pin/watch for creator-center UI changes in your integration tests"],"tags":["douyin","dom-selector","browser-automation"],"backgroundTag":"selector-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}