jackwener/OpenCLI · error · ArgumentError
标题不能超过 30 字
Error message
标题不能超过 30 字
What it means
ArgumentError thrown when the publish title exceeds 30 characters (title.length > 30). Douyin enforces a 30-char limit on video titles, so the library validates it up front.
Source
Thrown at clis/douyin/publish.js:124
{ name: 'hotspot', default: '', help: '关联热点词' },
{ name: 'no_safety_check', type: 'bool', default: false, help: '跳过内容安全检测' },
{ name: 'sync_toutiao', type: 'bool', default: false, help: '同步发布到头条' },
],
columns: ['status', 'aweme_id', 'url', 'publish_time'],
func: async (page, kwargs) => {
// ── Fail-fast validation ────────────────────────────────────────────
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 fileSize = fs.statSync(videoPath).size;
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 timingTs = toUnixSeconds(kwargs.schedule);
validateTiming(timingTs);
const visibilityType = VISIBILITY_MAP[kwargs.visibility] ?? 0;
const coverPath = kwargs.cover;
if (coverPath) {
if (!fs.existsSync(path.resolve(coverPath))) {
throw new ArgumentError(`封面文件不存在: ${path.resolve(coverPath)}`);
}
}
// ── Phase 1: upload credentials ────────────────────────────────────
const credentials = await getUploadAuthV5Credentials(page);
// ── Phase 2: Apply TOS upload URL ───────────────────────────────────
const tosUploadInfo = await applyVideoUploadInner(fileSize, credentials);View on GitHub (pinned to 49907e53dc)
Solutions
- Shorten the title to 30 characters or fewer.
- Trim the title programmatically before calling (accounting for surrogate pairs if using emoji).
- Move extra text into caption (up to 1000 chars) instead of the title.
- Count length with Array.from(title).length to approximate user-perceived length before trimming.
Example fix
// before
const title = '我的超长视频标题...超过三十个字的一段很长的描述文字继续';
await publish({ video, title });
// after
const raw = '我的超长视频标题...';
const title = Array.from(raw).slice(0, 30).join('');
await publish({ video, title }); Defensive patterns
Strategy: validation
Validate before calling
const title = Array.from(rawTitle);
if (title.length > 30) throw new Error(`title too long (${title.length}/30): trim before publishing`); Try / catch
try {
await publish({ video, title: rawTitle });
} catch (e) {
if (String(e.message).includes('标题不能超过 30 字')) {
const trimmed = Array.from(rawTitle).slice(0, 30).join('');
return publish({ video, title: trimmed });
}
throw e;
} Prevention
- Trim/validate titles to 30 code points before calling publish.
- Remember JS .length counts UTF-16 units — use Array.from for emoji-heavy titles.
- Move long text into caption (limit 1000 chars) instead of title.
- Add a unit test asserting generated titles meet the limit.
When it happens
Trigger: Passing --title (or kwargs.title) whose string length is 31+ — note this is JS string length, so emoji/CJK count per code unit (clis/douyin/publish.js:124).
Common situations: Long descriptive titles; titles with emoji where surrogate pairs inflate .length; titles assembled dynamically from templates exceeding the cap; localized text longer than expected.
Related errors
- --${name} is too long (max 60 chars): ${JSON.stringify(raw)}
- List name too long: ${name.length} chars (max ${NAME_MAX})
- Description too long: ${description.length} chars (max ${DES
- <train-no> must not be empty
- <train-no> "${trainNo}" does not look like a 12306 internal
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/3466b05baccdea52.
Report an issue: GitHub.