{"record":{"id":"3fa9e8236f4c3621","repo":"jackwener/OpenCLI","slug":"failed-to-fill-title","errorCode":null,"errorMessage":"Failed to fill title","messagePattern":"Failed to fill title","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/weixin/create-draft.js","lineNumber":298,"sourceCode":"    browser: true,\n    navigateBefore: false,\n    args: [\n        { name: 'title', required: true, help: '文章标题 (最长64字)' },\n        { name: 'content', required: true, positional: true, help: '文章正文' },\n        { name: 'author', help: '作者名 (最长8字)' },\n        { name: 'cover-image', help: '封面图片路径 (会先上传到正文再设为封面)' },\n        { name: 'summary', help: '文章摘要' },\n        { name: 'timeout', type: 'int', required: false, default: 180, help: 'Max seconds for the overall command (default: 180)' },\n    ],\n    columns: ['status', 'detail'],\n\n    func: async (page, kwargs) => {\n        try {\n            const coverImage = kwargs['cover-image'] ? resolveCoverImage(kwargs['cover-image']) : null;\n            await navigateToEditor(page);\n\n            const titleResult = await fillField(page, 'textarea#title', kwargs.title);\n            if (!titleResult?.ok) throw new CommandExecutionError('Failed to fill title');\n            if (kwargs.author) {\n                const authorResult = await fillField(page, 'input#author', kwargs.author);\n                if (!authorResult?.ok) throw new CommandExecutionError('Failed to fill author');\n            }\n            const contentResult = await fillContent(page, kwargs.content);\n            if (!contentResult?.ok) throw new CommandExecutionError('Failed to fill content');\n\n            if (coverImage) {\n                await uploadContentImage(page, coverImage);\n                const coverSet = await selectCoverFromContent(page);\n                if (coverSet !== true) {\n                    throw new CommandExecutionError('WeChat uploaded the image but did not confirm it as the draft cover.');\n                }\n            }\n\n            if (kwargs.summary) {\n                const summaryResult = await fillField(page, 'textarea#js_description', kwargs.summary);\n                if (!summaryResult?.ok) throw new CommandExecutionError('Failed to fill summary');","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/weixin/create-draft.js#L280-L316","documentation":"This CommandExecutionError is thrown by the weixin create-draft command when fillField() fails to set the article title in the WeChat Official Account editor. fillField() runs an in-page script that queries textarea#title; if the element is absent it returns {ok:false, reason:'field not found'}, and any non-ok result triggers this throw. It effectively means the expected title field never appeared or was not interactable after navigateToEditor().","triggerScenarios":"Calling the create-draft command where document.querySelector('textarea#title') is null inside the page at fill time: the editor page did not render the title textarea (WeChat DOM changed, slow load exceeding the fixed 4s wait in navigateToEditor, or a different editor layout was served). fillField itself only returns ok:false for 'field not found' — it does not fail on invalid values.","commonSituations":"WeChat changes its editor markup so textarea#title no longer exists; the mp.weixin.qq.com editor loads slowly (network latency, heavy account media library) and the fixed page.wait(4) elapses before the field is attached; an A/B or regional variant of the editor renders different selectors; a partially logged-in or rate-limited session lands on a page that still has the token but not the standard editor.","solutions":["Re-run the command once — transient slow rendering past the fixed 4-second wait is the most common cause; a retry usually finds the field.","Verify login state is fully valid (re-authenticate the WeChat session); a degraded session can land on a non-standard page missing the editor.","Inspect the live editor page and confirm textarea#title exists; if WeChat renamed it, update the selector in clis/weixin/create-draft.js (fillField call for the title).","Increase the wait after navigating to the editor URL (navigateToEditor uses page.wait(4)) or add an explicit wait-for-selector for textarea#title before filling."],"exampleFix":"// before\nconst titleResult = await fillField(page, 'textarea#title', kwargs.title);\nif (!titleResult?.ok) throw new CommandExecutionError('Failed to fill title');\n// after\nawait page.waitForSelector('textarea#title', { timeout: 15000 }); // or equivalent explicit wait\nconst titleResult = await fillField(page, 'textarea#title', kwargs.title);\nif (!titleResult?.ok) throw new CommandExecutionError('Failed to fill title: ' + (titleResult?.reason ?? 'unknown'));","handlingStrategy":"retry","validationCode":"const hasTitle = await page.evaluate('!!document.querySelector(\"textarea#title\")');\nif (hasTitle !== true) throw new Error('WeChat editor title field not present; aborting before fill.');","typeGuard":null,"tryCatchPattern":"try {\n  await createDraft({ title, author, content });\n} catch (e) {\n  if (e instanceof CommandExecutionError && /Failed to fill title/.test(e.message)) {\n    // retry once after delay, or re-authenticate the WeChat session\n  } else throw e;\n}","preventionTips":["Verify the WeChat session is freshly logged in before running create-draft.","Keep selectors in the CLI updated after WeChat editor redesigns; smoke-test on one draft first.","Wrap the command in a bounded retry (1-2 attempts with a few seconds delay) since fixed waits race slow editor loads.","Check the editor manually in a browser if the error repeats — confirms whether textarea#title still exists."],"tags":["puppeteer","dom-selector","wechat","automation"],"backgroundTag":"dom-element-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}