jackwener/OpenCLI · error · ArgumentError
标题不能超过 30 字
Error message
标题不能超过 30 字
What it means
The draft command enforces Douyin's 30-character title limit client-side. If kwargs.title (required) exceeds 30 JavaScript string units, an ArgumentError is thrown. Note the check uses .length (UTF-16 code units), so some emoji count as 2.
Source
Thrown at clis/douyin/draft.js:317
{ name: 'video', required: true, positional: true, help: '视频文件路径' },
{ name: 'title', required: true, help: '视频标题(≤30字)' },
{ name: 'caption', default: '', help: '正文内容(≤1000字,支持 #话题)' },
{ name: 'cover', default: '', help: '封面图片路径' },
{ name: 'visibility', default: 'public', choices: ['public', 'friends', 'private'] },
],
columns: ['status', 'draft_id'],
func: async (page, kwargs) => {
const videoPath = path.resolve(kwargs.video);
if (!fs.existsSync(videoPath)) {
throw new ArgumentError(`视频文件不存在: ${videoPath}`);
}
const ext = path.extname(videoPath).toLowerCase();
if (!['.mp4', '.mov', '.avi', '.webm'].includes(ext)) {
throw new ArgumentError(`不支持的视频格式: ${ext}(支持 mp4/mov/avi/webm)`);
}
const title = kwargs.title;
if (title.length > 30) {
throw new ArgumentError('标题不能超过 30 字');
}
const caption = kwargs.caption || '';
if (caption.length > 1000) {
throw new ArgumentError('正文不能超过 1000 字');
}
const coverPath = kwargs.cover;
if (coverPath) {
if (!fs.existsSync(path.resolve(coverPath))) {
throw new ArgumentError(`封面文件不存在: ${path.resolve(coverPath)}`);
}
}
if (!page.setFileInput) {
throw new CommandExecutionError('当前浏览器适配器不支持文件注入', '请使用 Browser Bridge 或支持 setFileInput 的浏览器模式');
}
const visibilityLabel = VISIBILITY_LABELS[kwargs.visibility] ?? VISIBILITY_LABELS.public;
await page.goto(DRAFT_UPLOAD_URL);
await page.wait({ selector: 'input[type="file"]', timeout: 20 });
await dismissKnownModals(page);View on GitHub (pinned to 49907e53dc)
Solutions
- Shorten the title to 30 characters or fewer before invoking the command
- Trim programmatically: `[...title].slice(0, 30).join('')` (array spread counts code points, safer than .slice)
- If the title is built from a template, move variable text to caption (limit 1000)
Example fix
// before
const title = '我的超长标题……(40个字)';
// after
const title = [...rawTitle].slice(0, 30).join(''); Defensive patterns
Strategy: validation
Validate before calling
const title = [...rawTitle].join('');
if ([...title].length > 30) throw new Error('Title exceeds Douyin 30-char limit'); Try / catch
try {
await cli.draft({ title, video });
} catch (e) {
if (e instanceof ArgumentError && e.message.includes('标题不能超过')) {
await cli.draft({ title: [...title].slice(0, 30).join(''), video });
} else throw e;
} Prevention
- Truncate titles at generation time using [...str].length (code points), not .length
- Keep titles under ~25 chars to leave room for emoji (which count as 2 UTF-16 units)
- Put descriptive text in the caption instead of the title
When it happens
Trigger: Calling `douyin draft --title "..."` with a title whose .length > 30, typically long descriptive titles or titles heavy with emoji (each emoji can count as 2 units).
Common situations: Reusing titles written for YouTube/Twitter with longer limits; emoji-decorated titles; titles generated programmatically by concatenating tags.
Related errors
- 正文不能超过 1000 字
- ${name} must be <= ${max}
- pubmed ${label} must be <= ${maxValue}
- archive search sort must be one of ${SORT_OPTIONS.join(', ')
- archive search mediatype must be one of ${MEDIATYPES.join(',
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/3030e327c2e71fa9.
Report an issue: GitHub.