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

  1. Shorten the title to 30 characters or fewer.
  2. Trim the title programmatically before calling (accounting for surrogate pairs if using emoji).
  3. Move extra text into caption (up to 1000 chars) instead of the title.
  4. 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

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


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/3466b05baccdea52. Report an issue: GitHub.