jackwener/OpenCLI · error · CommandExecutionError
WeChat save-draft button was not found.
Error message
WeChat save-draft button was not found.
What it means
Thrown by saveDraft when the in-page script cannot find an enabled button whose text is exactly 保存为草稿 (Save as draft). Without that button the library cannot trigger the draft save, so it throws before polling for confirmation.
Source
Thrown at clis/weixin/create-draft.js:263
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
}).map(function(el) {
return (el.innerText || el.textContent || '').replace(/\\s+/g, ' ').trim();
}).find(function(value) { return /已保存|保存成功/.test(value); }) || '';
return { visible: !!text, text: text };
})()`);
}
async function saveDraft(page) {
const before = await readSaveState(page);
const result = await evaluate(page, `(() => {
var button = Array.from(document.querySelectorAll('span, button, a')).find(function(el) {
return (el.textContent || '').trim() === '保存为草稿' && !el.disabled;
});
if (!button) return { ok: false };
button.click();
return { ok: true };
})()`);
if (!result?.ok) throw new CommandExecutionError('WeChat save-draft button was not found.');
for (let attempt = 0; attempt < 8; attempt++) {
await page.wait(1);
const state = await readSaveState(page);
if (state?.visible && (!before?.visible || state.text !== before.text)) return;
}
throw new CommandExecutionError('WeChat draft save was not confirmed by a fresh success status.');
}
export const createDraftCommand = cli({
site: 'weixin',
name: 'create-draft',
access: 'write',
description: '创建微信公众号图文草稿',
domain: WEIXIN_DOMAIN,
strategy: Strategy.COOKIE,
browser: true,
navigateBefore: false,View on GitHub (pinned to 49907e53dc)
Solutions
- Confirm the editor loaded fully (title textarea present) and the article has valid title/content so the save button is enabled.
- Open the live editor and inspect the save button's exact text/structure; update the matching logic if WeChat changed it (e.g. trim, includes, or query by class).
- Re-login and retry if the page was a session-expiry interstitial rather than the editor.
- Add a wait/poll for the button before the single click attempt to allow late rendering.
Example fix
// before
if (!result?.ok) throw new CommandExecutionError('WeChat save-draft button was not found.');
// after (in-page matching)
var els = Array.from(document.querySelectorAll('button, a, span'));
var button = els.find(function(el) {
return (el.textContent || '').trim().includes('保存为草稿') && !el.disabled;
});
if (!button) return { ok: false };
button.scrollIntoView();
button.click(); Defensive patterns
Strategy: validation
Validate before calling
await page.wait(4);
const canSave = await evaluate(page, 'Array.from(document.querySelectorAll("button, a, span")).some(el => (el.textContent || "").trim() === "保存为草稿" && !el.disabled)');
if (canSave !== true) throw new Error('save-draft button unavailable — check editor loaded and article has title/content'); Type guard
function isSaveClickResult(v) { return typeof v === 'object' && v !== null && typeof v.ok === 'boolean'; } Try / catch
try {
await createDraftCommand(opts);
} catch (e) {
if (/save-draft button was not found/i.test(e.message)) {
console.error('save button unavailable — verify session and editor state, then retry');
}
throw e;
} Prevention
- Ensure title and content are non-empty so the save button is enabled.
- Verify the editor fully loaded before the save step.
- Re-check the 保存为草稿 label and button structure after WeChat UI updates.
- Poll for the button instead of a single immediate lookup.
When it happens
Trigger: The article editor page is not fully loaded or the session expired so the toolbar/footer actions are missing, WeChat renamed or relabeled the save button, the button is disabled (e.g. empty title/content), the button exists but has extra whitespace or nested elements so textContent !== '保存为草稿', or a modal blocks rendering.
Common situations: WeChat UI updates changing the button label or structure; running against an unloaded/interstitial page; the editor disabled the save button because required fields are missing; rendering differences in headless mode.
Related errors
- Could not open WeChat image upload: ${opened?.reason || 'unk
- WeChat image upload returned a malformed editor image payloa
- Could not select WeChat image upload: ${selected?.reason ||
- Not a git repository
- Working tree not clean: ${status}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/208a7b5941434b5a.
Report an issue: GitHub.